about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
authorReverite <github@reverite.sh>2019-09-09 20:01:01 -0700
committerReverite <github@reverite.sh>2019-09-09 20:01:01 -0700
commit849e2bc4ca11892e701835a4696904d78b1ad325 (patch)
treeb579de6026e032167d7ba837b6f6cb3c7568ea24 /app
parent244196cf4a20005865bf0b9a1d99146e61e59ae4 (diff)
parent2aa0cdf7e6c44f252ffbcc991a5391c31386058d (diff)
Merge branch 'glitch' into production
Diffstat (limited to 'app')
-rw-r--r--app/javascript/flavours/glitch/components/account.js4
-rw-r--r--app/javascript/flavours/glitch/components/attachment_list.js5
-rw-r--r--app/javascript/flavours/glitch/components/column_back_button.js3
-rw-r--r--app/javascript/flavours/glitch/components/column_back_button_slim.js3
-rw-r--r--app/javascript/flavours/glitch/components/column_header.js21
-rw-r--r--app/javascript/flavours/glitch/components/domain.js4
-rw-r--r--app/javascript/flavours/glitch/components/icon.js41
-rw-r--r--app/javascript/flavours/glitch/components/icon_button.js5
-rw-r--r--app/javascript/flavours/glitch/components/icon_with_badge.js2
-rw-r--r--app/javascript/flavours/glitch/components/load_gap.js7
-rw-r--r--app/javascript/flavours/glitch/components/media_gallery.js4
-rw-r--r--app/javascript/flavours/glitch/components/notification_purge_buttons.js7
-rw-r--r--app/javascript/flavours/glitch/components/status_action_bar.js4
-rw-r--r--app/javascript/flavours/glitch/components/status_content.js9
-rw-r--r--app/javascript/flavours/glitch/components/status_icons.js22
-rw-r--r--app/javascript/flavours/glitch/components/status_prepend.js8
-rw-r--r--app/javascript/flavours/glitch/components/status_visibility_icon.js13
-rw-r--r--app/javascript/flavours/glitch/features/account/components/action_bar.js6
-rw-r--r--app/javascript/flavours/glitch/features/account/components/header.js4
-rw-r--r--app/javascript/flavours/glitch/features/account_gallery/components/media_item.js5
-rw-r--r--app/javascript/flavours/glitch/features/account_gallery/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js3
-rw-r--r--app/javascript/flavours/glitch/features/account_timeline/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/audio/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/blocks/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/bookmarked_statuses/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/community_timeline/components/column_settings.js4
-rw-r--r--app/javascript/flavours/glitch/features/community_timeline/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js2
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/header.js14
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/poll_form.js4
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/publisher.js4
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/search.js4
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/search_results.js10
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/textarea_icons.js4
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/upload.js2
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/upload_progress.js2
-rw-r--r--app/javascript/flavours/glitch/features/direct_timeline/components/column_settings.js4
-rw-r--r--app/javascript/flavours/glitch/features/direct_timeline/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/domain_blocks/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/emoji_picker/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/favourited_statuses/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/favourites/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/follow_requests/components/account_authorize.js4
-rw-r--r--app/javascript/flavours/glitch/features/follow_requests/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/followers/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/following/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/getting_started_misc/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/hashtag_timeline/components/column_settings.js4
-rw-r--r--app/javascript/flavours/glitch/features/hashtag_timeline/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/home_timeline/components/column_settings.js4
-rw-r--r--app/javascript/flavours/glitch/features/home_timeline/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/keyboard_shortcuts/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/list_adder/components/list.js3
-rw-r--r--app/javascript/flavours/glitch/features/list_editor/components/edit_list_form.js4
-rw-r--r--app/javascript/flavours/glitch/features/list_editor/components/search.js5
-rw-r--r--app/javascript/flavours/glitch/features/list_editor/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/list_timeline/index.js9
-rw-r--r--app/javascript/flavours/glitch/features/lists/components/new_list_form.js4
-rw-r--r--app/javascript/flavours/glitch/features/lists/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/local_settings/navigation/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/local_settings/navigation/item/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/local_settings/page/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/mutes/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/notifications/components/clear_column_button.js3
-rw-r--r--app/javascript/flavours/glitch/features/notifications/components/filter_bar.js11
-rw-r--r--app/javascript/flavours/glitch/features/notifications/components/follow.js3
-rw-r--r--app/javascript/flavours/glitch/features/notifications/components/overlay.js7
-rw-r--r--app/javascript/flavours/glitch/features/notifications/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/pinned_accounts_editor/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/pinned_statuses/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/public_timeline/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/reblogs/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/status/components/action_bar.js4
-rw-r--r--app/javascript/flavours/glitch/features/status/components/card.js7
-rw-r--r--app/javascript/flavours/glitch/features/status/components/detailed_status.js11
-rw-r--r--app/javascript/flavours/glitch/features/status/index.js7
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/actions_modal.js4
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/boost_modal.js7
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/column_header.js3
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/column_link.js7
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/columns_area.js7
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/confirmation_modal.js4
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/doodle_modal.js4
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/embed_modal.js4
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/favourite_modal.js7
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/list_panel.js2
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/media_modal.js9
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/mute_modal.js4
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/navigation_panel.js20
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js4
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/report_modal.js4
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/tabs_bar.js16
-rw-r--r--app/javascript/flavours/glitch/features/video/index.js17
94 files changed, 298 insertions, 265 deletions
diff --git a/app/javascript/flavours/glitch/components/account.js b/app/javascript/flavours/glitch/components/account.js
index 3fc18cb72..f3e58dfe3 100644
--- a/app/javascript/flavours/glitch/components/account.js
+++ b/app/javascript/flavours/glitch/components/account.js
@@ -19,8 +19,8 @@ const messages = defineMessages({
   unmute_notifications: { id: 'account.unmute_notifications', defaultMessage: 'You are currently muting notifications from @{name}. Click to unmute notifications' },
 });
 
-@injectIntl
-export default class Account extends ImmutablePureComponent {
+export default @injectIntl
+class Account extends ImmutablePureComponent {
 
   static propTypes = {
     account: ImmutablePropTypes.map.isRequired,
diff --git a/app/javascript/flavours/glitch/components/attachment_list.js b/app/javascript/flavours/glitch/components/attachment_list.js
index 8e5bb0e0b..08124d980 100644
--- a/app/javascript/flavours/glitch/components/attachment_list.js
+++ b/app/javascript/flavours/glitch/components/attachment_list.js
@@ -2,6 +2,7 @@ import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import ImmutablePureComponent from 'react-immutable-pure-component';
+import Icon from 'flavours/glitch/components/icon';
 
 const filename = url => url.split('/').pop().split('#')[0].split('?')[0];
 
@@ -24,7 +25,7 @@ export default class AttachmentList extends ImmutablePureComponent {
 
               return (
                 <li key={attachment.get('id')}>
-                  <a href={displayUrl} target='_blank' rel='noopener'><i className='fa fa-link' /> {filename(displayUrl)}</a>
+                  <a href={displayUrl} target='_blank' rel='noopener'><Icon id='link' /> {filename(displayUrl)}</a>
                 </li>
               );
             })}
@@ -36,7 +37,7 @@ export default class AttachmentList extends ImmutablePureComponent {
     return (
       <div className='attachment-list'>
         <div className='attachment-list__icon'>
-          <i className='fa fa-link' />
+          <Icon id='link' />
         </div>
 
         <ul className='attachment-list__list'>
diff --git a/app/javascript/flavours/glitch/components/column_back_button.js b/app/javascript/flavours/glitch/components/column_back_button.js
index 82556d22e..a0260e5af 100644
--- a/app/javascript/flavours/glitch/components/column_back_button.js
+++ b/app/javascript/flavours/glitch/components/column_back_button.js
@@ -1,6 +1,7 @@
 import React from 'react';
 import { FormattedMessage } from 'react-intl';
 import PropTypes from 'prop-types';
+import Icon from 'flavours/glitch/components/icon';
 
 export default class ColumnBackButton extends React.PureComponent {
 
@@ -25,7 +26,7 @@ export default class ColumnBackButton extends React.PureComponent {
   render () {
     return (
       <button onClick={this.handleClick} className='column-back-button'>
-        <i className='fa fa-fw fa-chevron-left column-back-button__icon' />
+        <Icon id='chevron-left' className='column-back-button__icon' fixedWidth />
         <FormattedMessage id='column_back_button.label' defaultMessage='Back' />
       </button>
     );
diff --git a/app/javascript/flavours/glitch/components/column_back_button_slim.js b/app/javascript/flavours/glitch/components/column_back_button_slim.js
index 38afd3df3..b57e3a057 100644
--- a/app/javascript/flavours/glitch/components/column_back_button_slim.js
+++ b/app/javascript/flavours/glitch/components/column_back_button_slim.js
@@ -1,6 +1,7 @@
 import React from 'react';
 import { FormattedMessage } from 'react-intl';
 import PropTypes from 'prop-types';
+import Icon from 'mastodon/components/icon';
 
 export default class ColumnBackButtonSlim extends React.PureComponent {
 
@@ -26,7 +27,7 @@ export default class ColumnBackButtonSlim extends React.PureComponent {
     return (
       <div className='column-back-button--slim'>
         <div role='button' tabIndex='0' onClick={this.handleClick} className='column-back-button column-back-button--slim-button'>
-          <i className='fa fa-fw fa-chevron-left column-back-button__icon' />
+          <Icon id='chevron-left' className='column-back-button__icon' fixedWidth />
           <FormattedMessage id='column_back_button.label' defaultMessage='Back' />
         </div>
       </div>
diff --git a/app/javascript/flavours/glitch/components/column_header.js b/app/javascript/flavours/glitch/components/column_header.js
index a0ff09986..3a064e90a 100644
--- a/app/javascript/flavours/glitch/components/column_header.js
+++ b/app/javascript/flavours/glitch/components/column_header.js
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
 import classNames from 'classnames';
 import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
 import ImmutablePropTypes from 'react-immutable-proptypes';
+import Icon from 'flavours/glitch/components/icon';
 
 import NotificationPurgeButtonsContainer from 'flavours/glitch/containers/notification_purge_buttons_container';
 
@@ -14,8 +15,8 @@ const messages = defineMessages({
   enterNotifCleaning : { id: 'notification_purge.start', defaultMessage: 'Enter notification cleaning mode' },
 });
 
-@injectIntl
-export default class ColumnHeader extends React.PureComponent {
+export default @injectIntl
+class ColumnHeader extends React.PureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
@@ -148,22 +149,22 @@ export default class ColumnHeader extends React.PureComponent {
     }
 
     if (multiColumn && pinned) {
-      pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><i className='fa fa fa-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' /> <FormattedMessage id='column_header.unpin' defaultMessage='Unpin' /></button>;
 
       moveButtons = (
         <div key='move-buttons' className='column-header__setting-arrows'>
-          <button title={formatMessage(messages.moveLeft)} aria-label={formatMessage(messages.moveLeft)} className='text-btn column-header__setting-btn' onClick={this.handleMoveLeft}><i className='fa fa-chevron-left' /></button>
-          <button title={formatMessage(messages.moveRight)} aria-label={formatMessage(messages.moveRight)} className='text-btn column-header__setting-btn' onClick={this.handleMoveRight}><i className='fa fa-chevron-right' /></button>
+          <button title={formatMessage(messages.moveLeft)} aria-label={formatMessage(messages.moveLeft)} className='text-btn column-header__setting-btn' onClick={this.handleMoveLeft}><Icon id='chevron-left' /></button>
+          <button title={formatMessage(messages.moveRight)} aria-label={formatMessage(messages.moveRight)} className='text-btn column-header__setting-btn' onClick={this.handleMoveRight}><Icon id='chevron-right' /></button>
         </div>
       );
     } else if (multiColumn) {
-      pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><i className='fa fa fa-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' /> <FormattedMessage id='column_header.pin' defaultMessage='Pin' /></button>;
     }
 
     if (!pinned && (multiColumn || showBackButton)) {
       backButton = (
         <button onClick={this.handleBackClick} className='column-header__back-button'>
-          <i className='fa fa-fw fa-chevron-left column-back-button__icon' />
+          <Icon id='chevron-left' className='column-back-button__icon' fixedWidth />
           <FormattedMessage id='column_back_button.label' defaultMessage='Back' />
         </button>
       );
@@ -179,7 +180,7 @@ export default class ColumnHeader extends React.PureComponent {
     }
 
     if (children || multiColumn) {
-      collapseButton = <button className={collapsibleButtonClassName} title={formatMessage(collapsed ? messages.show : messages.hide)} aria-label={formatMessage(collapsed ? messages.show : messages.hide)} aria-pressed={collapsed ? 'false' : 'true'} onClick={this.handleToggleClick}><i className='fa fa-sliders' /></button>;
+      collapseButton = <button className={collapsibleButtonClassName} title={formatMessage(collapsed ? messages.show : messages.hide)} aria-label={formatMessage(collapsed ? messages.show : messages.hide)} aria-pressed={collapsed ? 'false' : 'true'} onClick={this.handleToggleClick}><Icon id='sliders' /></button>;
     }
 
     const hasTitle = icon && title;
@@ -189,7 +190,7 @@ export default class ColumnHeader extends React.PureComponent {
         <h1 className={buttonClassName}>
           {hasTitle && (
             <button onClick={this.handleTitleClick}>
-              <i className={`fa fa-fw fa-${icon} column-header__icon`} />
+              <Icon id={icon} fixedWidth className='column-header__icon' />
               {title}
             </button>
           )}
@@ -206,7 +207,7 @@ export default class ColumnHeader extends React.PureComponent {
                 onClick={this.onEnterCleaningMode}
                 className={notifCleaningButtonClassName}
               >
-                <i className='fa fa-eraser' />
+                <Icon id='eraser' />
               </button>
             ) : null}
             {collapseButton}
diff --git a/app/javascript/flavours/glitch/components/domain.js b/app/javascript/flavours/glitch/components/domain.js
index 74174f83d..85729ca94 100644
--- a/app/javascript/flavours/glitch/components/domain.js
+++ b/app/javascript/flavours/glitch/components/domain.js
@@ -8,8 +8,8 @@ const messages = defineMessages({
   unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
 });
 
-@injectIntl
-export default class Account extends ImmutablePureComponent {
+export default @injectIntl
+class Account extends ImmutablePureComponent {
 
   static propTypes = {
     domain: PropTypes.string,
diff --git a/app/javascript/flavours/glitch/components/icon.js b/app/javascript/flavours/glitch/components/icon.js
index 8f55a0115..d8a17722f 100644
--- a/app/javascript/flavours/glitch/components/icon.js
+++ b/app/javascript/flavours/glitch/components/icon.js
@@ -1,26 +1,21 @@
-//  Package imports.
-import classNames from 'classnames';
-import PropTypes from 'prop-types';
 import React from 'react';
+import PropTypes from 'prop-types';
+import classNames from 'classnames';
 
-//  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;
-}
+export default class Icon extends React.PureComponent {
 
-//  Props.
-Icon.propTypes = {
-  className: PropTypes.string,
-  fullwidth: PropTypes.bool,
-  icon: PropTypes.string,
-};
+  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} />
+    );
+  }
+
+}
diff --git a/app/javascript/flavours/glitch/components/icon_button.js b/app/javascript/flavours/glitch/components/icon_button.js
index 521353238..6247f4571 100644
--- a/app/javascript/flavours/glitch/components/icon_button.js
+++ b/app/javascript/flavours/glitch/components/icon_button.js
@@ -3,6 +3,7 @@ import Motion from 'flavours/glitch/util/optional_motion';
 import spring from 'react-motion/lib/spring';
 import PropTypes from 'prop-types';
 import classNames from 'classnames';
+import Icon from 'flavours/glitch/components/icon';
 
 export default class IconButton extends React.PureComponent {
 
@@ -133,7 +134,7 @@ export default class IconButton extends React.PureComponent {
           tabIndex={tabIndex}
           disabled={disabled}
         >
-          <i className={`fa fa-fw fa-${icon}`} aria-hidden='true' />
+          <Icon id={icon} fixedWidth aria-hidden='true' />
         </button>
       );
     }
@@ -155,7 +156,7 @@ export default class IconButton extends React.PureComponent {
             tabIndex={tabIndex}
             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}
           </button>)
         }
diff --git a/app/javascript/flavours/glitch/components/icon_with_badge.js b/app/javascript/flavours/glitch/components/icon_with_badge.js
index 4a15ee5b4..219efc28c 100644
--- a/app/javascript/flavours/glitch/components/icon_with_badge.js
+++ b/app/javascript/flavours/glitch/components/icon_with_badge.js
@@ -6,7 +6,7 @@ const formatNumber = num => num > 40 ? '40+' : num;
 
 const IconWithBadge = ({ id, count, className }) => (
   <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>}
   </i>
 );
diff --git a/app/javascript/flavours/glitch/components/load_gap.js b/app/javascript/flavours/glitch/components/load_gap.js
index 012303ae1..fe3f60a58 100644
--- a/app/javascript/flavours/glitch/components/load_gap.js
+++ b/app/javascript/flavours/glitch/components/load_gap.js
@@ -1,13 +1,14 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { injectIntl, defineMessages } from 'react-intl';
+import Icon from 'flavours/glitch/components/icon';
 
 const messages = defineMessages({
   load_more: { id: 'status.load_more', defaultMessage: 'Load more' },
 });
 
-@injectIntl
-export default class LoadGap extends React.PureComponent {
+export default @injectIntl
+class LoadGap extends React.PureComponent {
 
   static propTypes = {
     disabled: PropTypes.bool,
@@ -25,7 +26,7 @@ export default class LoadGap extends React.PureComponent {
 
     return (
       <button className='load-more load-gap' disabled={disabled} onClick={this.handleClick} aria-label={intl.formatMessage(messages.load_more)}>
-        <i className='fa fa-ellipsis-h' />
+        <Icon id='ellipsis-h' />
       </button>
     );
   }
diff --git a/app/javascript/flavours/glitch/components/media_gallery.js b/app/javascript/flavours/glitch/components/media_gallery.js
index 28b369d09..a5a89e2f1 100644
--- a/app/javascript/flavours/glitch/components/media_gallery.js
+++ b/app/javascript/flavours/glitch/components/media_gallery.js
@@ -254,8 +254,8 @@ class Item extends React.PureComponent {
 
 }
 
-@injectIntl
-export default class MediaGallery extends React.PureComponent {
+export default @injectIntl
+class MediaGallery extends React.PureComponent {
 
   static propTypes = {
     sensitive: PropTypes.bool,
diff --git a/app/javascript/flavours/glitch/components/notification_purge_buttons.js b/app/javascript/flavours/glitch/components/notification_purge_buttons.js
index e0c1543b0..3c7d67109 100644
--- a/app/javascript/flavours/glitch/components/notification_purge_buttons.js
+++ b/app/javascript/flavours/glitch/components/notification_purge_buttons.js
@@ -10,6 +10,7 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { defineMessages, injectIntl } from 'react-intl';
 import ImmutablePureComponent from 'react-immutable-pure-component';
+import Icon from 'flavours/glitch/components/icon';
 
 const messages = defineMessages({
   btnAll : { id: 'notification_purge.btn_all', defaultMessage: 'Select\nall' },
@@ -18,8 +19,8 @@ const messages = defineMessages({
   btnApply : { id: 'notification_purge.btn_apply', defaultMessage: 'Clear\nselected' },
 });
 
-@injectIntl
-export default class NotificationPurgeButtons extends ImmutablePureComponent {
+export default @injectIntl
+class NotificationPurgeButtons extends ImmutablePureComponent {
 
   static propTypes = {
     onDeleteMarked : PropTypes.func.isRequired,
@@ -49,7 +50,7 @@ export default class NotificationPurgeButtons extends ImmutablePureComponent {
         </button>
 
         <button onClick={this.props.onDeleteMarked}>
-          <i className='fa fa-trash' /><br />{intl.formatMessage(messages.btnApply)}
+          <Icon id='trash' /><br />{intl.formatMessage(messages.btnApply)}
         </button>
       </div>
     );
diff --git a/app/javascript/flavours/glitch/components/status_action_bar.js b/app/javascript/flavours/glitch/components/status_action_bar.js
index 4ef518f5e..60b370622 100644
--- a/app/javascript/flavours/glitch/components/status_action_bar.js
+++ b/app/javascript/flavours/glitch/components/status_action_bar.js
@@ -48,8 +48,8 @@ const obfuscatedCount = count => {
   }
 };
 
-@injectIntl
-export default class StatusActionBar extends ImmutablePureComponent {
+export default @injectIntl
+class StatusActionBar extends ImmutablePureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
diff --git a/app/javascript/flavours/glitch/components/status_content.js b/app/javascript/flavours/glitch/components/status_content.js
index c34464fde..209350440 100644
--- a/app/javascript/flavours/glitch/components/status_content.js
+++ b/app/javascript/flavours/glitch/components/status_content.js
@@ -5,6 +5,7 @@ import { isRtl } from 'flavours/glitch/util/rtl';
 import { FormattedMessage } from 'react-intl';
 import Permalink from './permalink';
 import classnames from 'classnames';
+import Icon from 'flavours/glitch/components/icon';
 import { autoPlayGif } from 'flavours/glitch/util/initial_state';
 import { decode as decodeIDNA } from 'flavours/glitch/util/idna';
 
@@ -289,10 +290,10 @@ export default class StatusContent extends React.PureComponent {
           key='0'
         />,
         mediaIcon ? (
-          <i
-            className={
-              `fa fa-fw fa-${mediaIcon} status__content__spoiler-icon`
-            }
+          <Icon
+            fixedWidth
+            className='status__content__spoiler-icon'
+            id={mediaIcon}
             aria-hidden='true'
             key='1'
           />
diff --git a/app/javascript/flavours/glitch/components/status_icons.js b/app/javascript/flavours/glitch/components/status_icons.js
index 3dcfade3f..af86010f0 100644
--- a/app/javascript/flavours/glitch/components/status_icons.js
+++ b/app/javascript/flavours/glitch/components/status_icons.js
@@ -7,6 +7,7 @@ import { defineMessages, injectIntl } from 'react-intl';
 //  Mastodon imports.
 import IconButton from './icon_button';
 import VisibilityIcon from './status_visibility_icon';
+import Icon from 'flavours/glitch/components/icon';
 
 //  Messages for use with internationalization stuff.
 const messages = defineMessages({
@@ -21,8 +22,8 @@ const messages = defineMessages({
   localOnly: { id: 'status.local_only', defaultMessage: 'Only visible from your instance' },
 });
 
-@injectIntl
-export default class StatusIcons extends React.PureComponent {
+export default @injectIntl
+class StatusIcons extends React.PureComponent {
 
   static propTypes = {
     status: ImmutablePropTypes.map.isRequired,
@@ -74,21 +75,26 @@ export default class StatusIcons extends React.PureComponent {
     return (
       <div className='status__info__icons'>
         {status.get('in_reply_to_id', null) !== null ? (
-          <i
-            className={`fa fa-fw fa-comment status__reply-icon`}
+          <Icon
+            className='status__reply-icon'
+            fixedWidth
+            id='comment'
             aria-hidden='true'
             title={intl.formatMessage(messages.inReplyTo)}
           />
         ) : null}
         {status.get('local_only') &&
-          <i
-            className={`fa fa-fw fa-home`}
+          <Icon
+            fixedWidth
+            id='home'
             aria-hidden='true'
             title={intl.formatMessage(messages.localOnly)}
           />}
         {mediaIcon ? (
-          <i
-            className={`fa fa-fw fa-${mediaIcon} status__media-icon`}
+          <Icon
+            fixedWidth
+            className='status__media-icon`'
+            id={mediaIcon}
             aria-hidden='true'
             title={this.mediaIconTitleText()}
           />
diff --git a/app/javascript/flavours/glitch/components/status_prepend.js b/app/javascript/flavours/glitch/components/status_prepend.js
index 481e6644e..344c4d423 100644
--- a/app/javascript/flavours/glitch/components/status_prepend.js
+++ b/app/javascript/flavours/glitch/components/status_prepend.js
@@ -3,6 +3,7 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { FormattedMessage } from 'react-intl';
+import Icon from 'flavours/glitch/components/icon';
 
 export default class StatusPrepend extends React.PureComponent {
 
@@ -80,10 +81,9 @@ export default class StatusPrepend extends React.PureComponent {
     return !type ? null : (
       <aside className={type === 'reblogged_by' || type === 'featured' ? 'status__prepend' : 'notification__message'}>
         <div className={type === 'reblogged_by' || type === 'featured' ? 'status__prepend-icon-wrapper' : 'notification__favourite-icon-wrapper'}>
-          <i
-            className={`fa fa-fw fa-${
-              type === 'favourite' ? 'star star-icon' : (type === 'featured' ? 'thumb-tack' : (type === 'poll' ? 'tasks' : 'retweet'))
-            } status__prepend-icon`}
+          <Icon
+            className={`status__prepend-icon ${type === 'favourite' ? 'star-icon' : ''}`}
+            id={type === 'favourite' ? 'star' : (type === 'featured' ? 'thumb-tack' : (type === 'poll' ? 'tasks' : 'retweet'))}
           />
         </div>
         <Message />
diff --git a/app/javascript/flavours/glitch/components/status_visibility_icon.js b/app/javascript/flavours/glitch/components/status_visibility_icon.js
index 5e7b8ed00..e2e0f30b8 100644
--- a/app/javascript/flavours/glitch/components/status_visibility_icon.js
+++ b/app/javascript/flavours/glitch/components/status_visibility_icon.js
@@ -3,6 +3,7 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { defineMessages, injectIntl } from 'react-intl';
 import ImmutablePureComponent from 'react-immutable-pure-component';
+import Icon from 'flavours/glitch/components/icon';
 
 const messages = defineMessages({
   public: { id: 'privacy.public.short', defaultMessage: 'Public' },
@@ -11,8 +12,8 @@ const messages = defineMessages({
   direct: { id: 'privacy.direct.short', defaultMessage: 'Direct' },
 });
 
-@injectIntl
-export default class VisibilityIcon extends ImmutablePureComponent {
+export default @injectIntl
+class VisibilityIcon extends ImmutablePureComponent {
 
   static propTypes = {
     visibility: PropTypes.string,
@@ -23,7 +24,7 @@ export default class VisibilityIcon extends ImmutablePureComponent {
   render() {
     const { withLabel, visibility, intl } = this.props;
 
-    const visibilityClass = {
+    const visibilityIcon = {
       public: 'globe',
       unlisted: 'unlock',
       private: 'lock',
@@ -32,8 +33,10 @@ export default class VisibilityIcon extends ImmutablePureComponent {
 
     const label = intl.formatMessage(messages[visibility]);
 
-    const icon = (<i
-      className={`status__visibility-icon fa fa-fw fa-${visibilityClass}`}
+    const icon = (<Icon
+      className='status__visibility-icon'
+      fixedWidth
+      id={visibilityIcon}
       title={label}
       aria-hidden='true'
     />);
diff --git a/app/javascript/flavours/glitch/features/account/components/action_bar.js b/app/javascript/flavours/glitch/features/account/components/action_bar.js
index a2c00c1c2..6576bff8e 100644
--- a/app/javascript/flavours/glitch/features/account/components/action_bar.js
+++ b/app/javascript/flavours/glitch/features/account/components/action_bar.js
@@ -8,8 +8,8 @@ import { me, isStaff } from 'flavours/glitch/util/initial_state';
 import { profileLink, accountAdminLink } from 'flavours/glitch/util/backend_links';
 import Icon from 'flavours/glitch/components/icon';
 
-@injectIntl
-export default class ActionBar extends React.PureComponent {
+export default @injectIntl
+class ActionBar extends React.PureComponent {
 
   static propTypes = {
     account: ImmutablePropTypes.map.isRequired,
@@ -31,7 +31,7 @@ export default class ActionBar extends React.PureComponent {
     if (account.get('acct') !== account.get('username')) {
       extraInfo = (
         <div className='account__disclaimer'>
-          <Icon icon='info-circle' fixedWidth /> <FormattedMessage
+          <Icon id='info-circle' fixedWidth /> <FormattedMessage
             id='account.disclaimer_full'
             defaultMessage="Information below may reflect the user's profile incompletely."
           />
diff --git a/app/javascript/flavours/glitch/features/account/components/header.js b/app/javascript/flavours/glitch/features/account/components/header.js
index 2c0ad74db..fc0202129 100644
--- a/app/javascript/flavours/glitch/features/account/components/header.js
+++ b/app/javascript/flavours/glitch/features/account/components/header.js
@@ -158,7 +158,7 @@ class Header extends ImmutablePureComponent {
     }
 
     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) {
@@ -256,7 +256,7 @@ class Header extends ImmutablePureComponent {
             <div className='account__header__tabs__buttons'>
               {actionBtn}
 
-              <DropdownMenuContainer items={menu} icon='ellipsis-v' size={24} direction='right' />
+              <DropdownMenuContainer items={menu} id='ellipsis-v' size={24} direction='right' />
             </div>
           </div>
 
diff --git a/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js b/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js
index d60e06715..bd3baa5c3 100644
--- a/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js
+++ b/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js
@@ -2,6 +2,7 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
+import Icon from 'flavours/glitch/components/icon';
 import { autoPlayGif, displayMedia } from 'flavours/glitch/util/initial_state';
 import classNames from 'classnames';
 import { decode } from 'blurhash';
@@ -97,7 +98,7 @@ export default class MediaItem extends ImmutablePureComponent {
     } else if (attachment.get('type') === 'audio') {
       thumbnail = (
         <span className='account-gallery__item__icons'>
-          <i className='fa fa-music' />
+          <Icon id='music' />
         </span>
       );
     } else if (attachment.get('type') === 'image') {
@@ -139,7 +140,7 @@ export default class MediaItem extends ImmutablePureComponent {
 
     const icon = (
       <span className='account-gallery__item__icons'>
-        <i className='fa fa-eye-slash' />
+        <Icon id='eye-slash' />
       </span>
     );
 
diff --git a/app/javascript/flavours/glitch/features/account_gallery/index.js b/app/javascript/flavours/glitch/features/account_gallery/index.js
index 66b938bea..597196567 100644
--- a/app/javascript/flavours/glitch/features/account_gallery/index.js
+++ b/app/javascript/flavours/glitch/features/account_gallery/index.js
@@ -45,8 +45,8 @@ class LoadMoreMedia extends ImmutablePureComponent {
 
 }
 
-@connect(mapStateToProps)
-export default class AccountGallery extends ImmutablePureComponent {
+export default @connect(mapStateToProps)
+class AccountGallery extends ImmutablePureComponent {
 
   static propTypes = {
     params: PropTypes.object.isRequired,
diff --git a/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js b/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js
index 1fab083db..fcaa7b494 100644
--- a/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js
+++ b/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js
@@ -5,6 +5,7 @@ import { FormattedMessage } from 'react-intl';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import AvatarOverlay from '../../../components/avatar_overlay';
 import DisplayName from '../../../components/display_name';
+import Icon from 'flavours/glitch/components/icon';
 
 export default class MovedNote extends ImmutablePureComponent {
 
@@ -35,7 +36,7 @@ export default class MovedNote extends ImmutablePureComponent {
     return (
       <div className='account__moved-note'>
         <div className='account__moved-note__message'>
-          <div className='account__moved-note__icon-wrapper'><i className='fa fa-fw fa-suitcase account__moved-note__icon' /></div>
+          <div className='account__moved-note__icon-wrapper'><Icon id='suitcase' className='account__moved-note__icon' fixedWidth /></div>
           <FormattedMessage id='account.moved_to' defaultMessage='{name} has moved to:' values={{ name: <bdi><strong dangerouslySetInnerHTML={displayNameHtml} /></bdi> }} />
         </div>
 
diff --git a/app/javascript/flavours/glitch/features/account_timeline/index.js b/app/javascript/flavours/glitch/features/account_timeline/index.js
index 93d8fc9ec..2f0859341 100644
--- a/app/javascript/flavours/glitch/features/account_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/account_timeline/index.js
@@ -27,8 +27,8 @@ const mapStateToProps = (state, { params: { accountId }, withReplies = false })
   };
 };
 
-@connect(mapStateToProps)
-export default class AccountTimeline extends ImmutablePureComponent {
+export default @connect(mapStateToProps)
+class AccountTimeline extends ImmutablePureComponent {
 
   static propTypes = {
     params: PropTypes.object.isRequired,
diff --git a/app/javascript/flavours/glitch/features/audio/index.js b/app/javascript/flavours/glitch/features/audio/index.js
index 0830a4684..cf0e85b73 100644
--- a/app/javascript/flavours/glitch/features/audio/index.js
+++ b/app/javascript/flavours/glitch/features/audio/index.js
@@ -198,8 +198,8 @@ class Audio extends React.PureComponent {
         <div className='video-player__controls active'>
           <div className='video-player__buttons-bar'>
             <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(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><Icon icon={muted ? 'volume-off' : 'volume-up'} 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 id={muted ? 'volume-off' : 'volume-up'} fixedWidth /></button>
 
               <div className='video-player__volume' onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}>
                 <div className='video-player__volume__current' style={{ width: `${volumeWidth}px` }} />
diff --git a/app/javascript/flavours/glitch/features/blocks/index.js b/app/javascript/flavours/glitch/features/blocks/index.js
index 2d0f10ae7..8a84f5a55 100644
--- a/app/javascript/flavours/glitch/features/blocks/index.js
+++ b/app/javascript/flavours/glitch/features/blocks/index.js
@@ -21,9 +21,9 @@ const mapStateToProps = state => ({
   hasMore: !!state.getIn(['user_lists', 'blocks', 'next']),
 });
 
-@connect(mapStateToProps)
+export default @connect(mapStateToProps)
 @injectIntl
-export default class Blocks extends ImmutablePureComponent {
+class Blocks extends ImmutablePureComponent {
 
   static propTypes = {
     params: PropTypes.object.isRequired,
diff --git a/app/javascript/flavours/glitch/features/bookmarked_statuses/index.js b/app/javascript/flavours/glitch/features/bookmarked_statuses/index.js
index c57aba37b..7d550e362 100644
--- a/app/javascript/flavours/glitch/features/bookmarked_statuses/index.js
+++ b/app/javascript/flavours/glitch/features/bookmarked_statuses/index.js
@@ -21,9 +21,9 @@ const mapStateToProps = state => ({
   hasMore: !!state.getIn(['status_lists', 'bookmarks', 'next']),
 });
 
-@connect(mapStateToProps)
+export default @connect(mapStateToProps)
 @injectIntl
-export default class Bookmarks extends ImmutablePureComponent {
+class Bookmarks extends ImmutablePureComponent {
 
   static propTypes = {
     dispatch: PropTypes.func.isRequired,
diff --git a/app/javascript/flavours/glitch/features/community_timeline/components/column_settings.js b/app/javascript/flavours/glitch/features/community_timeline/components/column_settings.js
index 72828967f..69a4699ac 100644
--- a/app/javascript/flavours/glitch/features/community_timeline/components/column_settings.js
+++ b/app/javascript/flavours/glitch/features/community_timeline/components/column_settings.js
@@ -10,8 +10,8 @@ const messages = defineMessages({
   settings: { id: 'home.settings', defaultMessage: 'Column settings' },
 });
 
-@injectIntl
-export default class ColumnSettings extends React.PureComponent {
+export default @injectIntl
+class ColumnSettings extends React.PureComponent {
 
   static propTypes = {
     settings: ImmutablePropTypes.map.isRequired,
diff --git a/app/javascript/flavours/glitch/features/community_timeline/index.js b/app/javascript/flavours/glitch/features/community_timeline/index.js
index 24126e5bc..cb7d72c53 100644
--- a/app/javascript/flavours/glitch/features/community_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/community_timeline/index.js
@@ -25,9 +25,9 @@ const mapStateToProps = (state, { onlyMedia, columnId }) => {
   };
 };
 
-@connect(mapStateToProps)
+export default @connect(mapStateToProps)
 @injectIntl
-export default class CommunityTimeline extends React.PureComponent {
+class CommunityTimeline extends React.PureComponent {
 
   static defaultProps = {
     onlyMedia: false,
diff --git a/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js b/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js
index f812be7a9..60fee9b7f 100644
--- a/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js
+++ b/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js
@@ -185,7 +185,7 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent
     if (on !== null && typeof on !== 'undefined') {
       prefix = <Toggle checked={on} onChange={this.handleClick} />;
     } else if (icon) {
-      prefix = <Icon className='icon' fullwidth icon={icon} />
+      prefix = <Icon className='icon' fixedWidth id={icon} />
     }
 
     return (
diff --git a/app/javascript/flavours/glitch/features/compose/components/header.js b/app/javascript/flavours/glitch/features/compose/components/header.js
index 8b0f540ef..5b456b717 100644
--- a/app/javascript/flavours/glitch/features/compose/components/header.js
+++ b/app/javascript/flavours/glitch/features/compose/components/header.js
@@ -82,13 +82,13 @@ class Header extends ImmutablePureComponent {
           aria-label={intl.formatMessage(messages.start)}
           title={intl.formatMessage(messages.start)}
           to='/getting-started'
-        ><Icon icon='asterisk' /></Link>
+        ><Icon id='asterisk' /></Link>
         {renderForColumn('HOME', (
           <Link
             aria-label={intl.formatMessage(messages.home_timeline)}
             title={intl.formatMessage(messages.home_timeline)}
             to='/timelines/home'
-          ><Icon icon='home' /></Link>
+          ><Icon id='home' /></Link>
         ))}
         {renderForColumn('NOTIFICATIONS', (
           <Link
@@ -97,7 +97,7 @@ class Header extends ImmutablePureComponent {
             to='/notifications'
           >
             <span className='icon-badge-wrapper'>
-              <Icon icon='bell' />
+              <Icon id='bell' />
               { showNotificationsBadge && unreadNotifications > 0 && <div className='icon-badge' />}
             </span>
           </Link>
@@ -107,27 +107,27 @@ class Header extends ImmutablePureComponent {
             aria-label={intl.formatMessage(messages.community)}
             title={intl.formatMessage(messages.community)}
             to='/timelines/public/local'
-          ><Icon icon='users' /></Link>
+          ><Icon id='users' /></Link>
         ))}
         {renderForColumn('PUBLIC', (
           <Link
             aria-label={intl.formatMessage(messages.public)}
             title={intl.formatMessage(messages.public)}
             to='/timelines/public'
-          ><Icon icon='globe' /></Link>
+          ><Icon id='globe' /></Link>
         ))}
         <a
           aria-label={intl.formatMessage(messages.settings)}
           onClick={onSettingsClick}
           href='#'
           title={intl.formatMessage(messages.settings)}
-        ><Icon icon='cogs' /></a>
+        ><Icon id='cogs' /></a>
         <a
           aria-label={intl.formatMessage(messages.logout)}
           onClick={this.handleLogoutClick}
           href={ signOutLink }
           title={intl.formatMessage(messages.logout)}
-        ><Icon icon='sign-out' /></a>
+        ><Icon id='sign-out' /></a>
       </nav>
     );
   };
diff --git a/app/javascript/flavours/glitch/features/compose/components/poll_form.js b/app/javascript/flavours/glitch/features/compose/components/poll_form.js
index 21b5d3d73..d0678f2f0 100644
--- a/app/javascript/flavours/glitch/features/compose/components/poll_form.js
+++ b/app/javascript/flavours/glitch/features/compose/components/poll_form.js
@@ -79,7 +79,7 @@ class Option extends React.PureComponent {
         </label>
 
         <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>
       </li>
     );
@@ -132,7 +132,7 @@ class PollForm extends ImmutablePureComponent {
           {options.size < pollLimits.max_options && (
             <label className='poll__text editable'>
               <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>
           )}
         </ul>
diff --git a/app/javascript/flavours/glitch/features/compose/components/publisher.js b/app/javascript/flavours/glitch/features/compose/components/publisher.js
index f5eafc6fd..b8d9d98bf 100644
--- a/app/javascript/flavours/glitch/features/compose/components/publisher.js
+++ b/app/javascript/flavours/glitch/features/compose/components/publisher.js
@@ -58,7 +58,7 @@ class Publisher extends ImmutablePureComponent {
             text={
               <span>
                 <Icon
-                  icon={{
+                  id={{
                     public: 'globe',
                     unlisted: 'unlock',
                     private: 'lock',
@@ -80,7 +80,7 @@ class Publisher extends ImmutablePureComponent {
               return (
                 <span>
                   <Icon
-                    icon={{
+                    id={{
                       direct: 'envelope',
                       private: 'lock',
                       public: 'globe',
diff --git a/app/javascript/flavours/glitch/features/compose/components/search.js b/app/javascript/flavours/glitch/features/compose/components/search.js
index b25555d0f..29d195ecd 100644
--- a/app/javascript/flavours/glitch/features/compose/components/search.js
+++ b/app/javascript/flavours/glitch/features/compose/components/search.js
@@ -153,8 +153,8 @@ class Search extends React.PureComponent {
           role='button'
           tabIndex='0'
         >
-          <Icon icon='search' className={hasValue ? '' : 'active'} />
-          <Icon icon='times-circle' className={hasValue ? 'active' : ''} />
+          <Icon id='search' className={hasValue ? '' : 'active'} />
+          <Icon id='times-circle' className={hasValue ? 'active' : ''} />
         </div>
 
         <Overlay show={expanded && !hasValue} placement='bottom' target={this}>
diff --git a/app/javascript/flavours/glitch/features/compose/components/search_results.js b/app/javascript/flavours/glitch/features/compose/components/search_results.js
index 7220d8529..fa3487328 100644
--- a/app/javascript/flavours/glitch/features/compose/components/search_results.js
+++ b/app/javascript/flavours/glitch/features/compose/components/search_results.js
@@ -47,7 +47,7 @@ class SearchResults extends ImmutablePureComponent {
         <div className='drawer--results'>
           <div className='trends'>
             <div className='trends__header'>
-              <i className='fa fa-user-plus fa-fw' />
+              <Icon fixedWidth id='user-plus' />
               <FormattedMessage id='suggestions.header' defaultMessage='You might be interested in…' />
             </div>
 
@@ -82,7 +82,7 @@ class SearchResults extends ImmutablePureComponent {
       count   += results.get('accounts').size;
       accounts = (
         <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} />)}
 
@@ -95,7 +95,7 @@ class SearchResults extends ImmutablePureComponent {
       count   += results.get('statuses').size;
       statuses = (
         <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}/>)}
 
@@ -108,7 +108,7 @@ class SearchResults extends ImmutablePureComponent {
       count += results.get('hashtags').size;
       hashtags = (
         <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} />)}
 
@@ -121,7 +121,7 @@ class SearchResults extends ImmutablePureComponent {
     return (
       <div className='drawer--results'>
         <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 }} />
         </header>
 
diff --git a/app/javascript/flavours/glitch/features/compose/components/textarea_icons.js b/app/javascript/flavours/glitch/features/compose/components/textarea_icons.js
index ec696f9c3..b875fb15e 100644
--- a/app/javascript/flavours/glitch/features/compose/components/textarea_icons.js
+++ b/app/javascript/flavours/glitch/features/compose/components/textarea_icons.js
@@ -47,8 +47,8 @@ class TextareaIcons extends ImmutablePureComponent {
               title={intl.formatMessage(message)}
             >
               <Icon
-                fullwidth
-                icon={icon}
+                fixedWidth
+                id={icon}
               />
             </span>
           ) : null
diff --git a/app/javascript/flavours/glitch/features/compose/components/upload.js b/app/javascript/flavours/glitch/features/compose/components/upload.js
index f89145a52..425b0fe5e 100644
--- a/app/javascript/flavours/glitch/features/compose/components/upload.js
+++ b/app/javascript/flavours/glitch/features/compose/components/upload.js
@@ -44,7 +44,7 @@ export default class Upload extends ImmutablePureComponent {
           {({ scale }) => (
             <div style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>
               <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>
               </div>
             </div>
diff --git a/app/javascript/flavours/glitch/features/compose/components/upload_progress.js b/app/javascript/flavours/glitch/features/compose/components/upload_progress.js
index b00612983..493bb9ca5 100644
--- a/app/javascript/flavours/glitch/features/compose/components/upload_progress.js
+++ b/app/javascript/flavours/glitch/features/compose/components/upload_progress.js
@@ -22,7 +22,7 @@ export default class UploadProgress extends React.PureComponent {
 
     return (
       <div className='composer--upload_form--progress'>
-        <Icon icon={icon} />
+        <Icon id={icon} />
 
         <div className='message'>
           {message}
diff --git a/app/javascript/flavours/glitch/features/direct_timeline/components/column_settings.js b/app/javascript/flavours/glitch/features/direct_timeline/components/column_settings.js
index 5adb44f2c..ce14e2a9d 100644
--- a/app/javascript/flavours/glitch/features/direct_timeline/components/column_settings.js
+++ b/app/javascript/flavours/glitch/features/direct_timeline/components/column_settings.js
@@ -9,8 +9,8 @@ const messages = defineMessages({
   settings: { id: 'home.settings', defaultMessage: 'Column settings' },
 });
 
-@injectIntl
-export default class ColumnSettings extends React.PureComponent {
+export default @injectIntl
+class ColumnSettings extends React.PureComponent {
 
   static propTypes = {
     settings: ImmutablePropTypes.map.isRequired,
diff --git a/app/javascript/flavours/glitch/features/direct_timeline/index.js b/app/javascript/flavours/glitch/features/direct_timeline/index.js
index 6fe8a1ce8..e2c0a439a 100644
--- a/app/javascript/flavours/glitch/features/direct_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/direct_timeline/index.js
@@ -22,9 +22,9 @@ const mapStateToProps = state => ({
   conversationsMode: state.getIn(['settings', 'direct', 'conversations']),
 });
 
-@connect(mapStateToProps)
+export default @connect(mapStateToProps)
 @injectIntl
-export default class DirectTimeline extends React.PureComponent {
+class DirectTimeline extends React.PureComponent {
 
   static propTypes = {
     dispatch: PropTypes.func.isRequired,
diff --git a/app/javascript/flavours/glitch/features/domain_blocks/index.js b/app/javascript/flavours/glitch/features/domain_blocks/index.js
index f7d93a48e..49e0368d7 100644
--- a/app/javascript/flavours/glitch/features/domain_blocks/index.js
+++ b/app/javascript/flavours/glitch/features/domain_blocks/index.js
@@ -22,9 +22,9 @@ const mapStateToProps = state => ({
   hasMore: !!state.getIn(['domain_lists', 'blocks', 'next']),
 });
 
-@connect(mapStateToProps)
+export default @connect(mapStateToProps)
 @injectIntl
-export default class Blocks extends ImmutablePureComponent {
+class Blocks extends ImmutablePureComponent {
 
   static propTypes = {
     params: PropTypes.object.isRequired,
diff --git a/app/javascript/flavours/glitch/features/emoji_picker/index.js b/app/javascript/flavours/glitch/features/emoji_picker/index.js
index b255cf858..6e5518b0c 100644
--- a/app/javascript/flavours/glitch/features/emoji_picker/index.js
+++ b/app/javascript/flavours/glitch/features/emoji_picker/index.js
@@ -361,9 +361,9 @@ class EmojiPickerMenu extends React.PureComponent {
 
 }
 
-@connect(mapStateToProps, mapDispatchToProps)
+export default @connect(mapStateToProps, mapDispatchToProps)
 @injectIntl
-export default class EmojiPickerDropdown extends React.PureComponent {
+class EmojiPickerDropdown extends React.PureComponent {
 
   static propTypes = {
     custom_emojis: ImmutablePropTypes.list,
diff --git a/app/javascript/flavours/glitch/features/favourited_statuses/index.js b/app/javascript/flavours/glitch/features/favourited_statuses/index.js
index 0dae7dd53..719a31d6e 100644
--- a/app/javascript/flavours/glitch/features/favourited_statuses/index.js
+++ b/app/javascript/flavours/glitch/features/favourited_statuses/index.js
@@ -21,9 +21,9 @@ const mapStateToProps = state => ({
   hasMore: !!state.getIn(['status_lists', 'favourites', 'next']),
 });
 
-@connect(mapStateToProps)
+export default @connect(mapStateToProps)
 @injectIntl
-export default class Favourites extends ImmutablePureComponent {
+class Favourites extends ImmutablePureComponent {
 
   static propTypes = {
     dispatch: PropTypes.func.isRequired,
diff --git a/app/javascript/flavours/glitch/features/favourites/index.js b/app/javascript/flavours/glitch/features/favourites/index.js
index 81f0b24c4..5c33c8677 100644
--- a/app/javascript/flavours/glitch/features/favourites/index.js
+++ b/app/javascript/flavours/glitch/features/favourites/index.js
@@ -19,9 +19,9 @@ const mapStateToProps = (state, props) => ({
   accountIds: state.getIn(['user_lists', 'favourited_by', props.params.statusId]),
 });
 
-@connect(mapStateToProps)
+export default @connect(mapStateToProps)
 @injectIntl
-export default class Favourites extends ImmutablePureComponent {
+class Favourites extends ImmutablePureComponent {
 
   static propTypes = {
     params: PropTypes.object.isRequired,
diff --git a/app/javascript/flavours/glitch/features/follow_requests/components/account_authorize.js b/app/javascript/flavours/glitch/features/follow_requests/components/account_authorize.js
index dead0753f..bf145cb67 100644
--- a/app/javascript/flavours/glitch/features/follow_requests/components/account_authorize.js
+++ b/app/javascript/flavours/glitch/features/follow_requests/components/account_authorize.js
@@ -13,8 +13,8 @@ const messages = defineMessages({
   reject: { id: 'follow_request.reject', defaultMessage: 'Reject' },
 });
 
-@injectIntl
-export default class AccountAuthorize extends ImmutablePureComponent {
+export default @injectIntl
+class AccountAuthorize extends ImmutablePureComponent {
 
   static propTypes = {
     account: ImmutablePropTypes.map.isRequired,
diff --git a/app/javascript/flavours/glitch/features/follow_requests/index.js b/app/javascript/flavours/glitch/features/follow_requests/index.js
index 89340320e..a7e8f4b61 100644
--- a/app/javascript/flavours/glitch/features/follow_requests/index.js
+++ b/app/javascript/flavours/glitch/features/follow_requests/index.js
@@ -21,9 +21,9 @@ const mapStateToProps = state => ({
   hasMore: !!state.getIn(['user_lists', 'follow_requests', 'next']),
 });
 
-@connect(mapStateToProps)
+export default @connect(mapStateToProps)
 @injectIntl
-export default class FollowRequests extends ImmutablePureComponent {
+class FollowRequests extends ImmutablePureComponent {
 
   static propTypes = {
     params: PropTypes.object.isRequired,
diff --git a/app/javascript/flavours/glitch/features/followers/index.js b/app/javascript/flavours/glitch/features/followers/index.js
index 0f04b9ddc..b12efa774 100644
--- a/app/javascript/flavours/glitch/features/followers/index.js
+++ b/app/javascript/flavours/glitch/features/followers/index.js
@@ -24,8 +24,8 @@ const mapStateToProps = (state, props) => ({
   hasMore: !!state.getIn(['user_lists', 'followers', props.params.accountId, 'next']),
 });
 
-@connect(mapStateToProps)
-export default class Followers extends ImmutablePureComponent {
+export default @connect(mapStateToProps)
+class Followers extends ImmutablePureComponent {
 
   static propTypes = {
     params: PropTypes.object.isRequired,
diff --git a/app/javascript/flavours/glitch/features/following/index.js b/app/javascript/flavours/glitch/features/following/index.js
index 279c27500..9ea008e61 100644
--- a/app/javascript/flavours/glitch/features/following/index.js
+++ b/app/javascript/flavours/glitch/features/following/index.js
@@ -24,8 +24,8 @@ const mapStateToProps = (state, props) => ({
   hasMore: !!state.getIn(['user_lists', 'following', props.params.accountId, 'next']),
 });
 
-@connect(mapStateToProps)
-export default class Following extends ImmutablePureComponent {
+export default @connect(mapStateToProps)
+class Following extends ImmutablePureComponent {
 
   static propTypes = {
     params: PropTypes.object.isRequired,
diff --git a/app/javascript/flavours/glitch/features/getting_started_misc/index.js b/app/javascript/flavours/glitch/features/getting_started_misc/index.js
index ee4452472..570fe78bf 100644
--- a/app/javascript/flavours/glitch/features/getting_started_misc/index.js
+++ b/app/javascript/flavours/glitch/features/getting_started_misc/index.js
@@ -24,9 +24,9 @@ const messages = defineMessages({
   featured_users: { id: 'navigation_bar.featured_users', defaultMessage: 'Featured users' },
 });
 
-@connect()
+export default @connect()
 @injectIntl
-export default class gettingStartedMisc extends ImmutablePureComponent {
+class gettingStartedMisc extends ImmutablePureComponent {
 
   static propTypes = {
     intl: PropTypes.object.isRequired,
diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/components/column_settings.js b/app/javascript/flavours/glitch/features/hashtag_timeline/components/column_settings.js
index dc0ffee85..cdc138c8b 100644
--- a/app/javascript/flavours/glitch/features/hashtag_timeline/components/column_settings.js
+++ b/app/javascript/flavours/glitch/features/hashtag_timeline/components/column_settings.js
@@ -10,8 +10,8 @@ const messages = defineMessages({
   noOptions: { id: 'hashtag.column_settings.select.no_options_message', defaultMessage: 'No suggestions found' },
 });
 
-@injectIntl
-export default class ColumnSettings extends React.PureComponent {
+export default @injectIntl
+class ColumnSettings extends React.PureComponent {
 
   static propTypes = {
     settings: ImmutablePropTypes.map.isRequired,
diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js
index 21efaceea..d39505f46 100644
--- a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js
@@ -15,8 +15,8 @@ const mapStateToProps = (state, props) => ({
   hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}`, 'unread']) > 0,
 });
 
-@connect(mapStateToProps)
-export default class HashtagTimeline extends React.PureComponent {
+export default @connect(mapStateToProps)
+class HashtagTimeline extends React.PureComponent {
 
   disconnects = [];
 
diff --git a/app/javascript/flavours/glitch/features/home_timeline/components/column_settings.js b/app/javascript/flavours/glitch/features/home_timeline/components/column_settings.js
index d7692513e..df615db65 100644
--- a/app/javascript/flavours/glitch/features/home_timeline/components/column_settings.js
+++ b/app/javascript/flavours/glitch/features/home_timeline/components/column_settings.js
@@ -10,8 +10,8 @@ const messages = defineMessages({
   settings: { id: 'home.settings', defaultMessage: 'Column settings' },
 });
 
-@injectIntl
-export default class ColumnSettings extends React.PureComponent {
+export default @injectIntl
+class ColumnSettings extends React.PureComponent {
 
   static propTypes = {
     settings: ImmutablePropTypes.map.isRequired,
diff --git a/app/javascript/flavours/glitch/features/home_timeline/index.js b/app/javascript/flavours/glitch/features/home_timeline/index.js
index 8eb79fa60..defb1dcc1 100644
--- a/app/javascript/flavours/glitch/features/home_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/home_timeline/index.js
@@ -19,9 +19,9 @@ const mapStateToProps = state => ({
   isPartial: state.getIn(['timelines', 'home', 'isPartial']),
 });
 
-@connect(mapStateToProps)
+export default @connect(mapStateToProps)
 @injectIntl
-export default class HomeTimeline extends React.PureComponent {
+class HomeTimeline extends React.PureComponent {
 
   static propTypes = {
     dispatch: PropTypes.func.isRequired,
diff --git a/app/javascript/flavours/glitch/features/keyboard_shortcuts/index.js b/app/javascript/flavours/glitch/features/keyboard_shortcuts/index.js
index f7b475f8d..95daa6907 100644
--- a/app/javascript/flavours/glitch/features/keyboard_shortcuts/index.js
+++ b/app/javascript/flavours/glitch/features/keyboard_shortcuts/index.js
@@ -14,9 +14,9 @@ const mapStateToProps = state => ({
   collapseEnabled: state.getIn(['local_settings', 'collapsed', 'enabled']),
 });
 
-@connect(mapStateToProps)
+export default @connect(mapStateToProps)
 @injectIntl
-export default class KeyboardShortcuts extends ImmutablePureComponent {
+class KeyboardShortcuts extends ImmutablePureComponent {
 
   static propTypes = {
     intl: PropTypes.object.isRequired,
diff --git a/app/javascript/flavours/glitch/features/list_adder/components/list.js b/app/javascript/flavours/glitch/features/list_adder/components/list.js
index cb8eb7d7a..4666ca47b 100644
--- a/app/javascript/flavours/glitch/features/list_adder/components/list.js
+++ b/app/javascript/flavours/glitch/features/list_adder/components/list.js
@@ -6,6 +6,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 import IconButton from '../../../components/icon_button';
 import { defineMessages, injectIntl } from 'react-intl';
 import { removeFromListAdder, addToListAdder } from '../../../actions/lists';
+import Icon from 'flavours/glitch/components/icon';
 
 const messages = defineMessages({
   remove: { id: 'lists.account.remove', defaultMessage: 'Remove from list' },
@@ -53,7 +54,7 @@ class List extends ImmutablePureComponent {
       <div className='list'>
         <div className='list__wrapper'>
           <div className='list__display-name'>
-            <i className='fa fa-fw fa-list-ul column-link__icon' />
+            <Icon id='list-ul' className='column-link__icon' fixedWidth />
             {list.get('title')}
           </div>
 
diff --git a/app/javascript/flavours/glitch/features/list_editor/components/edit_list_form.js b/app/javascript/flavours/glitch/features/list_editor/components/edit_list_form.js
index bf5a8de35..a8cab2762 100644
--- a/app/javascript/flavours/glitch/features/list_editor/components/edit_list_form.js
+++ b/app/javascript/flavours/glitch/features/list_editor/components/edit_list_form.js
@@ -19,9 +19,9 @@ const mapDispatchToProps = dispatch => ({
   onSubmit: () => dispatch(submitListEditor(false)),
 });
 
-@connect(mapStateToProps, mapDispatchToProps)
+export default @connect(mapStateToProps, mapDispatchToProps)
 @injectIntl
-export default class ListForm extends React.PureComponent {
+class ListForm extends React.PureComponent {
 
   static propTypes = {
     value: PropTypes.string.isRequired,
diff --git a/app/javascript/flavours/glitch/features/list_editor/components/search.js b/app/javascript/flavours/glitch/features/list_editor/components/search.js
index 280632652..192643f77 100644
--- a/app/javascript/flavours/glitch/features/list_editor/components/search.js
+++ b/app/javascript/flavours/glitch/features/list_editor/components/search.js
@@ -2,6 +2,7 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { defineMessages } from 'react-intl';
 import classNames from 'classnames';
+import Icon from 'flavours/glitch/components/icon';
 
 const messages = defineMessages({
   search: { id: 'lists.search', defaultMessage: 'Search among people you follow' },
@@ -51,8 +52,8 @@ export default class Search extends React.PureComponent {
         </label>
 
         <div role='button' tabIndex='0' className='search__icon' onClick={this.handleClear}>
-          <i className={classNames('fa fa-search', { active: !hasValue })} />
-          <i aria-label={intl.formatMessage(messages.search)} className={classNames('fa fa-times-circle', { active: hasValue })} />
+          <Icon id='search' className={classNames({ active: !hasValue })} />
+          <Icon id='times-circle' aria-label={intl.formatMessage(messages.search)} className={classNames({ active: hasValue })} />
         </div>
       </div>
     );
diff --git a/app/javascript/flavours/glitch/features/list_editor/index.js b/app/javascript/flavours/glitch/features/list_editor/index.js
index 5f552b113..75b0de3d3 100644
--- a/app/javascript/flavours/glitch/features/list_editor/index.js
+++ b/app/javascript/flavours/glitch/features/list_editor/index.js
@@ -22,9 +22,9 @@ const mapDispatchToProps = dispatch => ({
   onReset: () => dispatch(resetListEditor()),
 });
 
-@connect(mapStateToProps, mapDispatchToProps)
+export default @connect(mapStateToProps, mapDispatchToProps)
 @injectIntl
-export default class ListEditor extends ImmutablePureComponent {
+class ListEditor extends ImmutablePureComponent {
 
   static propTypes = {
     listId: PropTypes.string.isRequired,
diff --git a/app/javascript/flavours/glitch/features/list_timeline/index.js b/app/javascript/flavours/glitch/features/list_timeline/index.js
index 0405073c5..8c3d0af51 100644
--- a/app/javascript/flavours/glitch/features/list_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/list_timeline/index.js
@@ -13,6 +13,7 @@ import { fetchList, deleteList, updateList } from 'flavours/glitch/actions/lists
 import { openModal } from 'flavours/glitch/actions/modal';
 import MissingIndicator from 'flavours/glitch/components/missing_indicator';
 import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
+import Icon from 'flavours/glitch/components/icon';
 
 const messages = defineMessages({
   deleteMessage: { id: 'confirmations.delete_list.message', defaultMessage: 'Are you sure you want to permanently delete this list?' },
@@ -27,9 +28,9 @@ const mapStateToProps = (state, props) => ({
   hasUnread: state.getIn(['timelines', `list:${props.params.id}`, 'unread']) > 0,
 });
 
-@connect(mapStateToProps)
+export default @connect(mapStateToProps)
 @injectIntl
-export default class ListTimeline extends React.PureComponent {
+class ListTimeline extends React.PureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
@@ -176,11 +177,11 @@ export default class ListTimeline extends React.PureComponent {
         >
           <div className='column-header__links'>
             <button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleEditClick}>
-              <i className='fa fa-pencil' /> <FormattedMessage id='lists.edit' defaultMessage='Edit list' />
+              <Icon id='pencil' /> <FormattedMessage id='lists.edit' defaultMessage='Edit list' />
             </button>
 
             <button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleDeleteClick}>
-              <i className='fa fa-trash' /> <FormattedMessage id='lists.delete' defaultMessage='Delete list' />
+              <Icon id='trash' /> <FormattedMessage id='lists.delete' defaultMessage='Delete list' />
             </button>
           </div>
 
diff --git a/app/javascript/flavours/glitch/features/lists/components/new_list_form.js b/app/javascript/flavours/glitch/features/lists/components/new_list_form.js
index eb5b6188a..cc78d30b7 100644
--- a/app/javascript/flavours/glitch/features/lists/components/new_list_form.js
+++ b/app/javascript/flavours/glitch/features/lists/components/new_list_form.js
@@ -20,9 +20,9 @@ const mapDispatchToProps = dispatch => ({
   onSubmit: () => dispatch(submitListEditor(true)),
 });
 
-@connect(mapStateToProps, mapDispatchToProps)
+export default @connect(mapStateToProps, mapDispatchToProps)
 @injectIntl
-export default class NewListForm extends React.PureComponent {
+class NewListForm extends React.PureComponent {
 
   static propTypes = {
     value: PropTypes.string.isRequired,
diff --git a/app/javascript/flavours/glitch/features/lists/index.js b/app/javascript/flavours/glitch/features/lists/index.js
index ad5240bd5..79bf2e601 100644
--- a/app/javascript/flavours/glitch/features/lists/index.js
+++ b/app/javascript/flavours/glitch/features/lists/index.js
@@ -31,9 +31,9 @@ const mapStateToProps = state => ({
   lists: getOrderedLists(state),
 });
 
-@connect(mapStateToProps)
+export default @connect(mapStateToProps)
 @injectIntl
-export default class Lists extends ImmutablePureComponent {
+class Lists extends ImmutablePureComponent {
 
   static propTypes = {
     params: PropTypes.object.isRequired,
diff --git a/app/javascript/flavours/glitch/features/local_settings/navigation/index.js b/app/javascript/flavours/glitch/features/local_settings/navigation/index.js
index 47f3d6d15..ab3a554bf 100644
--- a/app/javascript/flavours/glitch/features/local_settings/navigation/index.js
+++ b/app/javascript/flavours/glitch/features/local_settings/navigation/index.js
@@ -20,8 +20,8 @@ const messages = defineMessages({
   close: { id: 'settings.close', defaultMessage: 'Close' },
 });
 
-@injectIntl
-export default class LocalSettingsNavigation extends React.PureComponent {
+export default @injectIntl
+class LocalSettingsNavigation extends React.PureComponent {
 
   static propTypes = {
     index      : PropTypes.number,
diff --git a/app/javascript/flavours/glitch/features/local_settings/navigation/item/index.js b/app/javascript/flavours/glitch/features/local_settings/navigation/item/index.js
index 68a998b6c..4dec7d154 100644
--- a/app/javascript/flavours/glitch/features/local_settings/navigation/item/index.js
+++ b/app/javascript/flavours/glitch/features/local_settings/navigation/item/index.js
@@ -3,6 +3,8 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import classNames from 'classnames';
 
+import Icon from 'flavours/glitch/components/icon';
+
 //  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
 export default class LocalSettingsPage extends React.PureComponent {
@@ -42,7 +44,7 @@ export default class LocalSettingsPage extends React.PureComponent {
       active,
     }, className);
 
-    const iconElem = icon ? <i className={`fa fa-fw fa-${icon}`} /> : (textIcon ? <span className='text-icon-button'>{textIcon}</span> : null);
+    const iconElem = icon ? <Icon fixedWidth id={icon} /> : (textIcon ? <span className='text-icon-button'>{textIcon}</span> : null);
 
     if (href) return (
       <a
diff --git a/app/javascript/flavours/glitch/features/local_settings/page/index.js b/app/javascript/flavours/glitch/features/local_settings/page/index.js
index 64ed68876..e08c12c76 100644
--- a/app/javascript/flavours/glitch/features/local_settings/page/index.js
+++ b/app/javascript/flavours/glitch/features/local_settings/page/index.js
@@ -30,8 +30,8 @@ const messages = defineMessages({
   rewrite_mentions_username: { id: 'settings.rewrite_mentions_username', defaultMessage:  'Rewrite with username' },
 });
 
-@injectIntl
-export default class LocalSettingsPage extends React.PureComponent {
+export default @injectIntl
+class LocalSettingsPage extends React.PureComponent {
 
   static propTypes = {
     index    : PropTypes.number,
diff --git a/app/javascript/flavours/glitch/features/mutes/index.js b/app/javascript/flavours/glitch/features/mutes/index.js
index e5b5bb46d..7c20ca9b9 100644
--- a/app/javascript/flavours/glitch/features/mutes/index.js
+++ b/app/javascript/flavours/glitch/features/mutes/index.js
@@ -21,9 +21,9 @@ const mapStateToProps = state => ({
   hasMore: !!state.getIn(['user_lists', 'mutes', 'next']),
 });
 
-@connect(mapStateToProps)
+export default @connect(mapStateToProps)
 @injectIntl
-export default class Mutes extends ImmutablePureComponent {
+class Mutes extends ImmutablePureComponent {
 
   static propTypes = {
     params: PropTypes.object.isRequired,
diff --git a/app/javascript/flavours/glitch/features/notifications/components/clear_column_button.js b/app/javascript/flavours/glitch/features/notifications/components/clear_column_button.js
index 22a10753f..ee77cfb8e 100644
--- a/app/javascript/flavours/glitch/features/notifications/components/clear_column_button.js
+++ b/app/javascript/flavours/glitch/features/notifications/components/clear_column_button.js
@@ -1,6 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { FormattedMessage } from 'react-intl';
+import Icon from 'flavours/glitch/components/icon';
 
 export default class ClearColumnButton extends React.Component {
 
@@ -10,7 +11,7 @@ export default class ClearColumnButton extends React.Component {
 
   render () {
     return (
-      <button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.props.onClick}><i className='fa fa-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' /> <FormattedMessage id='notifications.clear' defaultMessage='Clear notifications' /></button>
     );
   }
 
diff --git a/app/javascript/flavours/glitch/features/notifications/components/filter_bar.js b/app/javascript/flavours/glitch/features/notifications/components/filter_bar.js
index 3457b7598..356ca4721 100644
--- a/app/javascript/flavours/glitch/features/notifications/components/filter_bar.js
+++ b/app/javascript/flavours/glitch/features/notifications/components/filter_bar.js
@@ -1,6 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import Icon from 'flavours/glitch/components/icon';
 
 const tooltips = defineMessages({
   mentions: { id: 'notifications.filter.mentions', defaultMessage: 'Mentions' },
@@ -63,35 +64,35 @@ class FilterBar extends React.PureComponent {
           onClick={this.onClick('mention')}
           title={intl.formatMessage(tooltips.mentions)}
         >
-          <i className='fa fa-fw fa-at' />
+          <Icon id='at' fixedWidth />
         </button>
         <button
           className={selectedFilter === 'favourite' ? 'active' : ''}
           onClick={this.onClick('favourite')}
           title={intl.formatMessage(tooltips.favourites)}
         >
-          <i className='fa fa-fw fa-star' />
+          <Icon id='star' fixedWidth />
         </button>
         <button
           className={selectedFilter === 'reblog' ? 'active' : ''}
           onClick={this.onClick('reblog')}
           title={intl.formatMessage(tooltips.boosts)}
         >
-          <i className='fa fa-fw fa-retweet' />
+          <Icon id='retweet' fixedWidth />
         </button>
         <button
           className={selectedFilter === 'poll' ? 'active' : ''}
           onClick={this.onClick('poll')}
           title={intl.formatMessage(tooltips.polls)}
         >
-          <i className='fa fa-fw fa-tasks' />
+          <Icon id='tasks' fixedWidth />
         </button>
         <button
           className={selectedFilter === 'follow' ? 'active' : ''}
           onClick={this.onClick('follow')}
           title={intl.formatMessage(tooltips.follows)}
         >
-          <i className='fa fa-fw fa-user-plus' />
+          <Icon id='user-plus' fixedWidth />
         </button>
       </div>
     );
diff --git a/app/javascript/flavours/glitch/features/notifications/components/follow.js b/app/javascript/flavours/glitch/features/notifications/components/follow.js
index ea81d9ab4..2b71f3107 100644
--- a/app/javascript/flavours/glitch/features/notifications/components/follow.js
+++ b/app/javascript/flavours/glitch/features/notifications/components/follow.js
@@ -10,6 +10,7 @@ import { HotKeys } from 'react-hotkeys';
 import Permalink from 'flavours/glitch/components/permalink';
 import AccountContainer from 'flavours/glitch/containers/account_container';
 import NotificationOverlayContainer from '../containers/overlay_container';
+import Icon from 'flavours/glitch/components/icon';
 
 export default class NotificationFollow extends ImmutablePureComponent {
 
@@ -78,7 +79,7 @@ export default class NotificationFollow extends ImmutablePureComponent {
         <div className='notification notification-follow focusable' tabIndex='0'>
           <div className='notification__message'>
             <div className='notification__favourite-icon-wrapper'>
-              <i className='fa fa-fw fa-user-plus' />
+              <Icon fixedWidth id='user-plus' />
             </div>
 
             <FormattedMessage
diff --git a/app/javascript/flavours/glitch/features/notifications/components/overlay.js b/app/javascript/flavours/glitch/features/notifications/components/overlay.js
index e56f9c628..f3ccafc06 100644
--- a/app/javascript/flavours/glitch/features/notifications/components/overlay.js
+++ b/app/javascript/flavours/glitch/features/notifications/components/overlay.js
@@ -9,13 +9,14 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import { defineMessages, injectIntl } from 'react-intl';
+import Icon from 'flavours/glitch/components/icon';
 
 const messages = defineMessages({
   markForDeletion: { id: 'notification.markForDeletion', defaultMessage: 'Mark for deletion' },
 });
 
-@injectIntl
-export default class NotificationOverlay extends ImmutablePureComponent {
+export default @injectIntl
+class NotificationOverlay extends ImmutablePureComponent {
 
   static propTypes = {
     notification    : ImmutablePropTypes.map.isRequired,
@@ -47,7 +48,7 @@ export default class NotificationOverlay extends ImmutablePureComponent {
       >
         <div className='wrappy'>
           <div className='ckbox' aria-hidden='true' title={label}>
-            {active ? (<i className='fa fa-check' />) : ''}
+            {active ? (<Icon id='check' />) : ''}
           </div>
         </div>
       </div>
diff --git a/app/javascript/flavours/glitch/features/notifications/index.js b/app/javascript/flavours/glitch/features/notifications/index.js
index bf805c69a..bd1af97a9 100644
--- a/app/javascript/flavours/glitch/features/notifications/index.js
+++ b/app/javascript/flavours/glitch/features/notifications/index.js
@@ -67,9 +67,9 @@ const mapDispatchToProps = dispatch => ({
   dispatch,
 });
 
-@connect(mapStateToProps, mapDispatchToProps)
+export default @connect(mapStateToProps, mapDispatchToProps)
 @injectIntl
-export default class Notifications extends React.PureComponent {
+class Notifications extends React.PureComponent {
 
   static propTypes = {
     columnId: PropTypes.string,
diff --git a/app/javascript/flavours/glitch/features/pinned_accounts_editor/index.js b/app/javascript/flavours/glitch/features/pinned_accounts_editor/index.js
index 7484e458e..5f03c7e93 100644
--- a/app/javascript/flavours/glitch/features/pinned_accounts_editor/index.js
+++ b/app/javascript/flavours/glitch/features/pinned_accounts_editor/index.js
@@ -21,9 +21,9 @@ const mapDispatchToProps = dispatch => ({
   onReset: () => dispatch(resetPinnedAccountsEditor()),
 });
 
-@connect(mapStateToProps, mapDispatchToProps)
+export default @connect(mapStateToProps, mapDispatchToProps)
 @injectIntl
-export default class PinnedAccountsEditor extends ImmutablePureComponent {
+class PinnedAccountsEditor extends ImmutablePureComponent {
 
   static propTypes = {
     onClose: PropTypes.func.isRequired,
diff --git a/app/javascript/flavours/glitch/features/pinned_statuses/index.js b/app/javascript/flavours/glitch/features/pinned_statuses/index.js
index f56d70176..8d406ddf4 100644
--- a/app/javascript/flavours/glitch/features/pinned_statuses/index.js
+++ b/app/javascript/flavours/glitch/features/pinned_statuses/index.js
@@ -18,9 +18,9 @@ const mapStateToProps = state => ({
   hasMore: !!state.getIn(['status_lists', 'pins', 'next']),
 });
 
-@connect(mapStateToProps)
+export default @connect(mapStateToProps)
 @injectIntl
-export default class PinnedStatuses extends ImmutablePureComponent {
+class PinnedStatuses extends ImmutablePureComponent {
 
   static propTypes = {
     dispatch: PropTypes.func.isRequired,
diff --git a/app/javascript/flavours/glitch/features/public_timeline/index.js b/app/javascript/flavours/glitch/features/public_timeline/index.js
index e5f5171aa..4bcf3da9d 100644
--- a/app/javascript/flavours/glitch/features/public_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/public_timeline/index.js
@@ -25,9 +25,9 @@ const mapStateToProps = (state, { onlyMedia, columnId }) => {
   };
 };
 
-@connect(mapStateToProps)
+export default @connect(mapStateToProps)
 @injectIntl
-export default class PublicTimeline extends React.PureComponent {
+class PublicTimeline extends React.PureComponent {
 
   static defaultProps = {
     onlyMedia: false,
diff --git a/app/javascript/flavours/glitch/features/reblogs/index.js b/app/javascript/flavours/glitch/features/reblogs/index.js
index 14f44a20a..1fc26b0d7 100644
--- a/app/javascript/flavours/glitch/features/reblogs/index.js
+++ b/app/javascript/flavours/glitch/features/reblogs/index.js
@@ -19,9 +19,9 @@ const mapStateToProps = (state, props) => ({
   accountIds: state.getIn(['user_lists', 'reblogged_by', props.params.statusId]),
 });
 
-@connect(mapStateToProps)
+export default @connect(mapStateToProps)
 @injectIntl
-export default class Reblogs extends ImmutablePureComponent {
+class Reblogs extends ImmutablePureComponent {
 
   static propTypes = {
     params: PropTypes.object.isRequired,
diff --git a/app/javascript/flavours/glitch/features/status/components/action_bar.js b/app/javascript/flavours/glitch/features/status/components/action_bar.js
index 8291319c3..c48bfaccd 100644
--- a/app/javascript/flavours/glitch/features/status/components/action_bar.js
+++ b/app/javascript/flavours/glitch/features/status/components/action_bar.js
@@ -32,8 +32,8 @@ const messages = defineMessages({
   copy: { id: 'status.copy', defaultMessage: 'Copy link to status' },
 });
 
-@injectIntl
-export default class ActionBar extends React.PureComponent {
+export default @injectIntl
+class ActionBar extends React.PureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
diff --git a/app/javascript/flavours/glitch/features/status/components/card.js b/app/javascript/flavours/glitch/features/status/components/card.js
index 108b6e3b2..f5ce1b766 100644
--- a/app/javascript/flavours/glitch/features/status/components/card.js
+++ b/app/javascript/flavours/glitch/features/status/components/card.js
@@ -5,6 +5,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 import punycode from 'punycode';
 import classnames from 'classnames';
 import { decode as decodeIDNA } from 'flavours/glitch/util/idna';
+import Icon from 'flavours/glitch/components/icon';
 
 const getHostname = url => {
   const parser = document.createElement('a');
@@ -170,8 +171,8 @@ export default class Card extends React.PureComponent {
 
             <div className='status-card__actions'>
               <div>
-                <button onClick={this.handleEmbedClick}><i className={`fa fa-${iconVariant}`} /></button>
-                {horizontal && <a href={card.get('url')} target='_blank' rel='noopener'><i className='fa fa-external-link' /></a>}
+                <button onClick={this.handleEmbedClick}><Icon id={iconVariant} /></button>
+                {horizontal && <a href={card.get('url')} target='_blank' rel='noopener'><Icon id='external-link' /></a>}
               </div>
             </div>
           </div>
@@ -193,7 +194,7 @@ export default class Card extends React.PureComponent {
     } else {
       embed = (
         <div className='status-card__image'>
-          <i className='fa fa-file-text' />
+          <Icon id='file-text' />
         </div>
       );
     }
diff --git a/app/javascript/flavours/glitch/features/status/components/detailed_status.js b/app/javascript/flavours/glitch/features/status/components/detailed_status.js
index 5242c7d5c..f7d71eec2 100644
--- a/app/javascript/flavours/glitch/features/status/components/detailed_status.js
+++ b/app/javascript/flavours/glitch/features/status/components/detailed_status.js
@@ -16,6 +16,7 @@ import VisibilityIcon from 'flavours/glitch/components/status_visibility_icon';
 import scheduleIdleTask from 'flavours/glitch/util/schedule_idle_task';
 import classNames from 'classnames';
 import PollContainer from 'flavours/glitch/containers/poll_container';
+import Icon from 'flavours/glitch/components/icon';
 
 export default class DetailedStatus extends ImmutablePureComponent {
 
@@ -197,11 +198,11 @@ export default class DetailedStatus extends ImmutablePureComponent {
     }
 
     if (status.get('visibility') === 'private') {
-      reblogLink = <i className={`fa fa-${reblogIcon}`} />;
+      reblogLink = <Icon id={reblogIcon} />;
     } else if (this.context.router) {
       reblogLink = (
         <Link to={`/statuses/${status.get('id')}/reblogs`} className='detailed-status__link'>
-          <i className={`fa fa-${reblogIcon}`} />
+          <Icon id={reblogIcon} />
           <span className='detailed-status__reblogs'>
             <FormattedNumber value={status.get('reblogs_count')} />
           </span>
@@ -210,7 +211,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
     } else {
       reblogLink = (
         <a href={`/interact/${status.get('id')}?type=reblog`} className='detailed-status__link' onClick={this.handleModalLink}>
-          <i className={`fa fa-${reblogIcon}`} />
+          <Icon id={reblogIcon} />
           <span className='detailed-status__reblogs'>
             <FormattedNumber value={status.get('reblogs_count')} />
           </span>
@@ -221,7 +222,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
     if (this.context.router) {
       favouriteLink = (
         <Link to={`/statuses/${status.get('id')}/favourites`} className='detailed-status__link'>
-          <i className='fa fa-star' />
+          <Icon id='star' />
           <span className='detailed-status__favorites'>
             <FormattedNumber value={status.get('favourites_count')} />
           </span>
@@ -230,7 +231,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
     } else {
       favouriteLink = (
         <a href={`/interact/${status.get('id')}?type=favourite`} className='detailed-status__link' onClick={this.handleModalLink}>
-          <i className='fa fa-star' />
+          <Icon id='star' />
           <span className='detailed-status__favorites'>
             <FormattedNumber value={status.get('favourites_count')} />
           </span>
diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js
index 58b8a8cbb..e91ab5f3a 100644
--- a/app/javascript/flavours/glitch/features/status/index.js
+++ b/app/javascript/flavours/glitch/features/status/index.js
@@ -43,6 +43,7 @@ import { boostModal, favouriteModal, deleteModal } from 'flavours/glitch/util/in
 import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from 'flavours/glitch/util/fullscreen';
 import { autoUnfoldCW } from 'flavours/glitch/util/content_warning';
 import { textForScreenReader, defaultMediaVisibility } from 'flavours/glitch/components/status';
+import Icon from 'flavours/glitch/components/icon';
 
 const messages = defineMessages({
   deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
@@ -139,9 +140,9 @@ const makeMapStateToProps = () => {
   return mapStateToProps;
 };
 
-@injectIntl
+export default @injectIntl
 @connect(makeMapStateToProps)
-export default class Status extends ImmutablePureComponent {
+class Status extends ImmutablePureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
@@ -549,7 +550,7 @@ export default class Status extends ImmutablePureComponent {
           onClick={this.handleHeaderClick}
           showBackButton
           extraButton={(
-            <button className='column-header__button' title={intl.formatMessage(!isExpanded ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(!isExpanded ? messages.revealAll : messages.hideAll)} onClick={this.handleToggleAll} aria-pressed={!isExpanded ? 'false' : 'true'}><i className={`fa fa-${!isExpanded ? 'eye-slash' : 'eye'}`} /></button>
+            <button className='column-header__button' title={intl.formatMessage(!isExpanded ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(!isExpanded ? messages.revealAll : messages.hideAll)} onClick={this.handleToggleAll} aria-pressed={!isExpanded ? 'false' : 'true'}><Icon id={status.get('hidden') ? 'eye-slash' : 'eye'} /></button>
           )}
         />
 
diff --git a/app/javascript/flavours/glitch/features/ui/components/actions_modal.js b/app/javascript/flavours/glitch/features/ui/components/actions_modal.js
index 724f1c764..9e63f653a 100644
--- a/app/javascript/flavours/glitch/features/ui/components/actions_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/actions_modal.js
@@ -68,8 +68,8 @@ export default class ActionsModal extends ImmutablePureComponent {
               return (
                 <Icon
                   className='icon'
-                  fullwidth
-                  icon={icon}
+                  fixedWidth
+                  id={icon}
                 />
               );
             default:
diff --git a/app/javascript/flavours/glitch/features/ui/components/boost_modal.js b/app/javascript/flavours/glitch/features/ui/components/boost_modal.js
index 600e4422f..3421b953a 100644
--- a/app/javascript/flavours/glitch/features/ui/components/boost_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/boost_modal.js
@@ -8,6 +8,7 @@ import Avatar from 'flavours/glitch/components/avatar';
 import RelativeTimestamp from 'flavours/glitch/components/relative_timestamp';
 import DisplayName from 'flavours/glitch/components/display_name';
 import AttachmentList from 'flavours/glitch/components/attachment_list';
+import Icon from 'flavours/glitch/components/icon';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 
 const messages = defineMessages({
@@ -15,8 +16,8 @@ const messages = defineMessages({
   reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
 });
 
-@injectIntl
-export default class BoostModal extends ImmutablePureComponent {
+export default @injectIntl
+class BoostModal extends ImmutablePureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
@@ -91,7 +92,7 @@ export default class BoostModal extends ImmutablePureComponent {
             { missingMediaDescription ?
                 <FormattedMessage id='boost_modal.missing_description' defaultMessage='This toot contains some media without description' />
               :
-                <FormattedMessage id='boost_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <i className='fa fa-retweet' /></span> }} />
+                <FormattedMessage id='boost_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon id='retweet' /></span> }} />
             }
           </div>
           <Button text={intl.formatMessage(buttonText)} onClick={this.handleReblog} ref={this.setRef} />
diff --git a/app/javascript/flavours/glitch/features/ui/components/column_header.js b/app/javascript/flavours/glitch/features/ui/components/column_header.js
index e8bdd8054..528ff73a6 100644
--- a/app/javascript/flavours/glitch/features/ui/components/column_header.js
+++ b/app/javascript/flavours/glitch/features/ui/components/column_header.js
@@ -1,6 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import classNames from 'classnames';
+import Icon from 'flavours/glitch/components/icon';
 
 export default class ColumnHeader extends React.PureComponent {
 
@@ -21,7 +22,7 @@ export default class ColumnHeader extends React.PureComponent {
     let iconElement = '';
 
     if (icon) {
-      iconElement = <i className={`fa fa-fw fa-${icon} column-header__icon`} />;
+      iconElement = <Icon id={icon} fixedWidth className='column-header__icon' />;
     }
 
     return (
diff --git a/app/javascript/flavours/glitch/features/ui/components/column_link.js b/app/javascript/flavours/glitch/features/ui/components/column_link.js
index 1b6d7d09e..d04b869b6 100644
--- a/app/javascript/flavours/glitch/features/ui/components/column_link.js
+++ b/app/javascript/flavours/glitch/features/ui/components/column_link.js
@@ -1,6 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Link } from 'react-router-dom';
+import Icon from 'flavours/glitch/components/icon';
 
 const ColumnLink = ({ icon, text, to, onClick, href, method, badge }) => {
   const badgeElement = typeof badge !== 'undefined' ? <span className='column-link__badge'>{badge}</span> : null;
@@ -8,7 +9,7 @@ const ColumnLink = ({ icon, text, to, onClick, href, method, badge }) => {
   if (href) {
     return (
       <a href={href} className='column-link' data-method={method}>
-        <i className={`fa fa-fw fa-${icon} column-link__icon`} />
+        <Icon id={icon} fixedWidth className='column-link__icon' />
         {text}
         {badgeElement}
       </a>
@@ -16,7 +17,7 @@ const ColumnLink = ({ icon, text, to, onClick, href, method, badge }) => {
   } else if (to) {
     return (
       <Link to={to} className='column-link'>
-        <i className={`fa fa-fw fa-${icon} column-link__icon`} />
+        <Icon id={icon} fixedWidth className='column-link__icon' />
         {text}
         {badgeElement}
       </Link>
@@ -29,7 +30,7 @@ const ColumnLink = ({ icon, text, to, onClick, href, method, badge }) => {
     }
     return (
       <a href='#' onClick={onClick && handleOnClick} className='column-link' tabIndex='0'>
-        <i className={`fa fa-fw fa-${icon} column-link__icon`} />
+        <Icon id={icon} fixedWidth className='column-link__icon' />
         {text}
         {badgeElement}
       </a>
diff --git a/app/javascript/flavours/glitch/features/ui/components/columns_area.js b/app/javascript/flavours/glitch/features/ui/components/columns_area.js
index 46df1f4ef..958b856db 100644
--- a/app/javascript/flavours/glitch/features/ui/components/columns_area.js
+++ b/app/javascript/flavours/glitch/features/ui/components/columns_area.js
@@ -25,6 +25,7 @@ import {
   ListTimeline,
   Directory,
 } from 'flavours/glitch/util/async-components';
+import Icon from 'flavours/glitch/components/icon';
 import ComposePanel from './compose_panel';
 import NavigationPanel from './navigation_panel';
 
@@ -51,8 +52,8 @@ const messages = defineMessages({
   publish: { id: 'compose_form.publish', defaultMessage: 'Toot' },
 });
 
-@component => injectIntl(component, { withRef: true })
-export default class ColumnsArea extends ImmutablePureComponent {
+export default @(component => injectIntl(component, { withRef: true }))
+class ColumnsArea extends ImmutablePureComponent {
 
   static contextTypes = {
     router: PropTypes.object.isRequired,
@@ -182,7 +183,7 @@ export default class ColumnsArea extends ImmutablePureComponent {
     const columnIndex = getIndex(this.context.router.history.location.pathname);
 
     if (singleColumn) {
-      const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null : <Link key='floating-action-button' to='/statuses/new' className='floating-action-button' aria-label={intl.formatMessage(messages.publish)}><i className='fa fa-pencil' /></Link>;
+      const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null : <Link key='floating-action-button' to='/statuses/new' className='floating-action-button' aria-label={intl.formatMessage(messages.publish)}><Icon id='pencil' /></Link>;
 
       const content = columnIndex !== -1 ? (
         <ReactSwipeableViews key='content' index={columnIndex} onChangeIndex={this.handleSwipe} onTransitionEnd={this.handleAnimationEnd} animateTransitions={shouldAnimate} springConfig={{ duration: '400ms', delay: '0s', easeFunction: 'ease' }} style={{ height: '100%' }} disabled={!swipeToChangeColumns}>
diff --git a/app/javascript/flavours/glitch/features/ui/components/confirmation_modal.js b/app/javascript/flavours/glitch/features/ui/components/confirmation_modal.js
index 970df30b6..47a49c0c7 100644
--- a/app/javascript/flavours/glitch/features/ui/components/confirmation_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/confirmation_modal.js
@@ -3,8 +3,8 @@ import PropTypes from 'prop-types';
 import { injectIntl, FormattedMessage } from 'react-intl';
 import Button from 'flavours/glitch/components/button';
 
-@injectIntl
-export default class ConfirmationModal extends React.PureComponent {
+export default @injectIntl
+class ConfirmationModal extends React.PureComponent {
 
   static propTypes = {
     message: PropTypes.node.isRequired,
diff --git a/app/javascript/flavours/glitch/features/ui/components/doodle_modal.js b/app/javascript/flavours/glitch/features/ui/components/doodle_modal.js
index 72f7f30b9..0d10204fc 100644
--- a/app/javascript/flavours/glitch/features/ui/components/doodle_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/doodle_modal.js
@@ -145,8 +145,8 @@ const mapDispatchToProps = dispatch => ({
  * - Ctrl + left mouse button: pick background
  * - Right mouse button: pick background
  */
-@connect(mapStateToProps, mapDispatchToProps)
-export default class DoodleModal extends ImmutablePureComponent {
+export default @connect(mapStateToProps, mapDispatchToProps)
+class DoodleModal extends ImmutablePureComponent {
 
   static propTypes = {
     options: ImmutablePropTypes.map,
diff --git a/app/javascript/flavours/glitch/features/ui/components/embed_modal.js b/app/javascript/flavours/glitch/features/ui/components/embed_modal.js
index b1643df1c..47c1c7925 100644
--- a/app/javascript/flavours/glitch/features/ui/components/embed_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/embed_modal.js
@@ -4,8 +4,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
 import { FormattedMessage, injectIntl } from 'react-intl';
 import api from 'flavours/glitch/util/api';
 
-@injectIntl
-export default class EmbedModal extends ImmutablePureComponent {
+export default @injectIntl
+class EmbedModal extends ImmutablePureComponent {
 
   static propTypes = {
     url: PropTypes.string.isRequired,
diff --git a/app/javascript/flavours/glitch/features/ui/components/favourite_modal.js b/app/javascript/flavours/glitch/features/ui/components/favourite_modal.js
index e0037a15f..176e7c487 100644
--- a/app/javascript/flavours/glitch/features/ui/components/favourite_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/favourite_modal.js
@@ -7,14 +7,15 @@ import StatusContent from 'flavours/glitch/components/status_content';
 import Avatar from 'flavours/glitch/components/avatar';
 import RelativeTimestamp from 'flavours/glitch/components/relative_timestamp';
 import DisplayName from 'flavours/glitch/components/display_name';
+import Icon from 'flavours/glitch/components/icon';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 
 const messages = defineMessages({
   favourite: { id: 'status.favourite', defaultMessage: 'Favourite' },
 });
 
-@injectIntl
-export default class FavouriteModal extends ImmutablePureComponent {
+export default @injectIntl
+class FavouriteModal extends ImmutablePureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
@@ -76,7 +77,7 @@ export default class FavouriteModal extends ImmutablePureComponent {
         </div>
 
         <div className='favourite-modal__action-bar'>
-          <div><FormattedMessage id='favourite_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <i className='fa fa-star' /></span> }} /></div>
+          <div><FormattedMessage id='favourite_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon id='star' /></span> }} /></div>
           <Button text={intl.formatMessage(messages.favourite)} onClick={this.handleFavourite} ref={this.setRef} />
         </div>
       </div>
diff --git a/app/javascript/flavours/glitch/features/ui/components/list_panel.js b/app/javascript/flavours/glitch/features/ui/components/list_panel.js
index b2e6925b7..354e35027 100644
--- a/app/javascript/flavours/glitch/features/ui/components/list_panel.js
+++ b/app/javascript/flavours/glitch/features/ui/components/list_panel.js
@@ -46,7 +46,7 @@ class ListPanel extends ImmutablePureComponent {
         <hr />
 
         {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>
     );
diff --git a/app/javascript/flavours/glitch/features/ui/components/media_modal.js b/app/javascript/flavours/glitch/features/ui/components/media_modal.js
index ce6660480..5d60c8a08 100644
--- a/app/javascript/flavours/glitch/features/ui/components/media_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/media_modal.js
@@ -9,6 +9,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import IconButton from 'flavours/glitch/components/icon_button';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import ImageLoader from './image_loader';
+import Icon from 'flavours/glitch/components/icon';
 
 const messages = defineMessages({
   close: { id: 'lightbox.close', defaultMessage: 'Close' },
@@ -16,8 +17,8 @@ const messages = defineMessages({
   next: { id: 'lightbox.next', defaultMessage: 'Next' },
 });
 
-@injectIntl
-export default class MediaModal extends ImmutablePureComponent {
+export default @injectIntl
+class MediaModal extends ImmutablePureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
@@ -100,8 +101,8 @@ export default class MediaModal extends ImmutablePureComponent {
     const index = this.getIndex();
     let pagination = [];
 
-    const leftNav  = media.size > 1 && <button tabIndex='0' className='media-modal__nav media-modal__nav--left' onClick={this.handlePrevClick} aria-label={intl.formatMessage(messages.previous)}><i className='fa fa-fw fa-chevron-left' /></button>;
-    const rightNav = media.size > 1 && <button tabIndex='0' className='media-modal__nav  media-modal__nav--right' onClick={this.handleNextClick} aria-label={intl.formatMessage(messages.next)}><i className='fa fa-fw fa-chevron-right' /></button>;
+    const leftNav  = media.size > 1 && <button tabIndex='0' className='media-modal__nav media-modal__nav--left' onClick={this.handlePrevClick} aria-label={intl.formatMessage(messages.previous)}><Icon id='chevron-left' fixedWidth /></button>;
+    const rightNav = media.size > 1 && <button tabIndex='0' className='media-modal__nav  media-modal__nav--right' onClick={this.handleNextClick} aria-label={intl.formatMessage(messages.next)}><Icon id='chevron-right' fixedWidth /></button>;
 
     if (media.size > 1) {
       pagination = media.map((item, i) => {
diff --git a/app/javascript/flavours/glitch/features/ui/components/mute_modal.js b/app/javascript/flavours/glitch/features/ui/components/mute_modal.js
index 0202b1ab1..3492eca69 100644
--- a/app/javascript/flavours/glitch/features/ui/components/mute_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/mute_modal.js
@@ -33,9 +33,9 @@ const mapDispatchToProps = dispatch => {
   };
 };
 
-@connect(mapStateToProps, mapDispatchToProps)
+export default @connect(mapStateToProps, mapDispatchToProps)
 @injectIntl
-export default class MuteModal extends React.PureComponent {
+class MuteModal extends React.PureComponent {
 
   static propTypes = {
     isSubmitting: PropTypes.bool.isRequired,
diff --git a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js
index a4f06f4c5..50e7d5c48 100644
--- a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js
+++ b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js
@@ -11,23 +11,23 @@ import TrendsContainer from 'flavours/glitch/features/getting_started/containers
 
 const NavigationPanel = ({ onOpenSettings }) => (
   <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>
     <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' 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' 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='/bookmarks'><Icon className='column-link__icon' icon='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>}
-    <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='/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' 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' 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' 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' 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' id='list-ul' fixedWidth /><FormattedMessage id='navigation_bar.lists' defaultMessage='Lists' /></NavLink>
 
     <ListPanel />
 
     <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>}
-    <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>
-    {!!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>}
+    {!!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' 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' id='users' fixedWidth /><FormattedMessage id='navigation_bar.follows_and_followers' defaultMessage='Follows and followers' /></a>}
 
     {showTrends && <div className='flex-spacer' />}
     {showTrends && <TrendsContainer />}
diff --git a/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js b/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js
index 3db9ec77d..7419e2cd9 100644
--- a/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js
@@ -159,9 +159,9 @@ const mapStateToProps = state => ({
   domain: state.getIn(['meta', 'domain']),
 });
 
-@connect(mapStateToProps)
+export default @connect(mapStateToProps)
 @injectIntl
-export default class OnboardingModal extends React.PureComponent {
+class OnboardingModal extends React.PureComponent {
 
   static propTypes = {
     onClose: PropTypes.func.isRequired,
diff --git a/app/javascript/flavours/glitch/features/ui/components/report_modal.js b/app/javascript/flavours/glitch/features/ui/components/report_modal.js
index 8be1d5856..9016b08d7 100644
--- a/app/javascript/flavours/glitch/features/ui/components/report_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/report_modal.js
@@ -37,9 +37,9 @@ const makeMapStateToProps = () => {
   return mapStateToProps;
 };
 
-@connect(makeMapStateToProps)
+export default @connect(makeMapStateToProps)
 @injectIntl
-export default class ReportModal extends ImmutablePureComponent {
+class ReportModal extends ImmutablePureComponent {
 
   static propTypes = {
     isSubmitting: PropTypes.bool,
diff --git a/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js b/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js
index dbd08aa2b..90e645a82 100644
--- a/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js
+++ b/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js
@@ -4,16 +4,16 @@ import { NavLink, withRouter } from 'react-router-dom';
 import { FormattedMessage, injectIntl } from 'react-intl';
 import { debounce } from 'lodash';
 import { isUserTouching } from 'flavours/glitch/util/is_mobile';
+import Icon from 'flavours/glitch/components/icon';
 import NotificationsCounterIcon from './notifications_counter_icon';
 
 export const links = [
-  <NavLink className='tabs-bar__link' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><i className='fa fa-fw fa-home' /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>,
+  <NavLink className='tabs-bar__link' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon id='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>,
   <NavLink className='tabs-bar__link' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>,
-
-  <NavLink className='tabs-bar__link' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><i className='fa fa-fw fa-users' /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>,
-  <NavLink className='tabs-bar__link' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><i className='fa fa-fw fa-globe' /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>,
-  <NavLink className='tabs-bar__link optional' to='/search' data-preview-title-id='tabs_bar.search' data-preview-icon='bell' ><i className='fa fa-fw fa-search' /><FormattedMessage id='tabs_bar.search' defaultMessage='Search' /></NavLink>,
-  <NavLink className='tabs-bar__link' style={{ flexGrow: '0', flexBasis: '30px' }} to='/getting-started' data-preview-title-id='getting_started.heading' data-preview-icon='bars' ><i className='fa fa-fw fa-bars' /></NavLink>,
+  <NavLink className='tabs-bar__link' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon id='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>,
+  <NavLink className='tabs-bar__link' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon id='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>,
+  <NavLink className='tabs-bar__link optional' to='/search' data-preview-title-id='tabs_bar.search' data-preview-icon='bell' ><Icon id='search' fixedWidth /><FormattedMessage id='tabs_bar.search' defaultMessage='Search' /></NavLink>,
+  <NavLink className='tabs-bar__link' style={{ flexGrow: '0', flexBasis: '30px' }} to='/getting-started' data-preview-title-id='getting_started.heading' data-preview-icon='bars' ><Icon id='bars' fixedWidth /></NavLink>,
 ];
 
 export function getIndex (path) {
@@ -24,9 +24,9 @@ export function getLink (index) {
   return links[index].props.to;
 }
 
-@injectIntl
+export default @injectIntl
 @withRouter
-export default class TabsBar extends React.PureComponent {
+class TabsBar extends React.PureComponent {
 
   static propTypes = {
     intl: PropTypes.object.isRequired,
diff --git a/app/javascript/flavours/glitch/features/video/index.js b/app/javascript/flavours/glitch/features/video/index.js
index 24368bef9..2659e0e91 100644
--- a/app/javascript/flavours/glitch/features/video/index.js
+++ b/app/javascript/flavours/glitch/features/video/index.js
@@ -6,6 +6,7 @@ import { throttle } from 'lodash';
 import classNames from 'classnames';
 import { isFullscreen, requestFullscreen, exitFullscreen } from 'flavours/glitch/util/fullscreen';
 import { displayMedia, useBlurhash } from 'flavours/glitch/util/initial_state';
+import Icon from 'flavours/glitch/components/icon';
 import { decode } from 'blurhash';
 
 const messages = defineMessages({
@@ -84,8 +85,8 @@ export const getPointerPosition = (el, event) => {
   return position;
 };
 
-@injectIntl
-export default class Video extends React.PureComponent {
+export default @injectIntl
+class Video extends React.PureComponent {
 
   static propTypes = {
     preview: PropTypes.string,
@@ -486,8 +487,8 @@ export default class Video extends React.PureComponent {
 
           <div className='video-player__buttons-bar'>
             <div className='video-player__buttons left'>
-              <button type='button' aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay}><i className={classNames('fa fa-fw', { 'fa-play': paused, 'fa-pause': !paused })} /></button>
-              <button type='button' aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><i className={classNames('fa fa-fw', { 'fa-volume-off': muted, 'fa-volume-up': !muted })} /></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 id={muted ? 'volume-off' : 'volume-up'} fixedWidth /></button>
               <div className='video-player__volume' onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}>
                 <div className='video-player__volume__current' style={{ width: `${volumeWidth}px` }} />
                 <span
@@ -509,10 +510,10 @@ export default class Video extends React.PureComponent {
             </div>
 
             <div className='video-player__buttons right'>
-              {(!onCloseVideo && !editable) && <button type='button' aria-label={intl.formatMessage(messages.hide)} onClick={this.toggleReveal}><i className='fa fa-fw fa-eye-slash' /></button>}
-              {(!fullscreen && onOpenVideo) && <button type='button' aria-label={intl.formatMessage(messages.expand)} onClick={this.handleOpenVideo}><i className='fa fa-fw fa-expand' /></button>}
-              {onCloseVideo && <button type='button' aria-label={intl.formatMessage(messages.close)} onClick={this.handleCloseVideo}><i className='fa fa-fw fa-compress' /></button>}
-              <button type='button' aria-label={intl.formatMessage(fullscreen ? messages.exit_fullscreen : messages.fullscreen)} onClick={this.toggleFullscreen}><i className={classNames('fa fa-fw', { 'fa-arrows-alt': !fullscreen, 'fa-compress': fullscreen })} /></button>
+              {(!onCloseVideo && !editable) && <button type='button' aria-label={intl.formatMessage(messages.hide)} onClick={this.toggleReveal}><Icon id='eye-slash' fixedWidth /></button>}
+              {(!fullscreen && onOpenVideo) && <button type='button' aria-label={intl.formatMessage(messages.expand)} onClick={this.handleOpenVideo}><Icon id='expand' fixedWidth /></button>}
+              {onCloseVideo && <button type='button' aria-label={intl.formatMessage(messages.close)} onClick={this.handleCloseVideo}><Icon id='compress' fixedWidth /></button>}
+              <button type='button' aria-label={intl.formatMessage(fullscreen ? messages.exit_fullscreen : messages.fullscreen)} onClick={this.toggleFullscreen}><Icon id={fullscreen ? 'compress' : 'arrows-alt'} fixedWidth /></button>
             </div>
           </div>
         </div>