From 38142182774ea772aacc88f26586512d6279267f Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 19 Oct 2020 19:38:49 +0300
Subject: [PATCH] Some initial work on replacing icons with FA5

---
 package.json                                  |   4 +
 src/App.scss                                  |   9 +-
 src/components/emoji_input/emoji_input.js     |   9 +
 src/components/emoji_input/emoji_input.vue    |   2 +-
 src/components/emoji_picker/emoji_picker.js   |  16 +-
 src/components/emoji_picker/emoji_picker.scss |   2 +-
 src/components/emoji_picker/emoji_picker.vue  |   4 +-
 src/components/extra_buttons/extra_buttons.js |   4 +
 .../extra_buttons/extra_buttons.vue           |   6 +-
 .../favorite_button/favorite_button.js        |  14 +-
 .../favorite_button/favorite_button.vue       |  33 ++--
 src/components/media_upload/media_upload.js   |   8 +
 src/components/media_upload/media_upload.vue  |  10 +-
 src/components/nav_panel/nav_panel.js         |  23 +++
 src/components/nav_panel/nav_panel.vue        | 160 +++++++++---------
 src/components/poll/poll_form.js              |  12 ++
 src/components/poll/poll_form.vue             |  16 +-
 .../post_status_form/post_status_form.js      |  17 ++
 .../post_status_form/post_status_form.vue     |  31 ++--
 src/components/react_button/react_button.js   |   4 +
 src/components/react_button/react_button.vue  |   6 +-
 src/components/reply_button/reply_button.js   |   4 +
 src/components/reply_button/reply_button.vue  |  28 ++-
 .../retweet_button/retweet_button.js          |   8 +-
 .../retweet_button/retweet_button.vue         |  48 ++++--
 .../scope_selector/scope_selector.js          |  15 ++
 .../scope_selector/scope_selector.vue         |  50 +++---
 src/components/status/status.js               |  49 +++++-
 src/components/status/status.scss             |  26 +--
 src/components/status/status.vue              |  70 ++++----
 src/components/timeline_menu/timeline_menu.js |  18 ++
 .../timeline_menu/timeline_menu.vue           |  32 ++--
 src/main.js                                   |   4 +
 yarn.lock                                     |  31 ++++
 34 files changed, 528 insertions(+), 245 deletions(-)

diff --git a/package.json b/package.json
index 75d9ee56..6bc285c8 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,10 @@
   "dependencies": {
     "@babel/runtime": "^7.7.6",
     "@chenfengyuan/vue-qrcode": "^1.0.0",
+    "@fortawesome/fontawesome-svg-core": "^1.2.32",
+    "@fortawesome/free-regular-svg-icons": "^5.15.1",
+    "@fortawesome/free-solid-svg-icons": "^5.15.1",
+    "@fortawesome/vue-fontawesome": "^2.0.0",
     "body-scroll-lock": "^2.6.4",
     "chromatism": "^3.0.0",
     "cropperjs": "^1.4.3",
diff --git a/src/App.scss b/src/App.scss
index e1e1bdd0..d34698e2 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -318,7 +318,7 @@ option {
   }
 }
 
-i[class*=icon-] {
+i[class*=icon-], .svg-inline--fa  {
   color: $fallback--icon;
   color: var(--icon, $fallback--icon);
 }
@@ -808,7 +808,12 @@ nav {
 }
 
 .button-icon {
-  font-size: 1.2em;
+  &i,
+  &.svg-inline--fa.fa-lg {
+    display: inline-block;
+    padding: 0 0.3em;
+    font-size: 1.1em;
+  }
 }
 
 @keyframes shakeError {
diff --git a/src/components/emoji_input/emoji_input.js b/src/components/emoji_input/emoji_input.js
index f0123447..87303d08 100644
--- a/src/components/emoji_input/emoji_input.js
+++ b/src/components/emoji_input/emoji_input.js
@@ -3,6 +3,15 @@ import EmojiPicker from '../emoji_picker/emoji_picker.vue'
 import { take } from 'lodash'
 import { findOffset } from '../../services/offset_finder/offset_finder.service.js'
 
+import { library } from '@fortawesome/fontawesome-svg-core'
+import {
+  faSmileBeam
+} from '@fortawesome/free-regular-svg-icons'
+
+library.add(
+  faSmileBeam
+)
+
 /**
  * EmojiInput - augmented inputs for emoji and autocomplete support in inputs
  * without having to give up the comfort of <input/> and <textarea/> elements
diff --git a/src/components/emoji_input/emoji_input.vue b/src/components/emoji_input/emoji_input.vue
index b9a74572..224e72cf 100644
--- a/src/components/emoji_input/emoji_input.vue
+++ b/src/components/emoji_input/emoji_input.vue
@@ -11,7 +11,7 @@
         class="emoji-picker-icon"
         @click.prevent="togglePicker"
       >
-        <i class="icon-smile" />
+        <FAIcon :icon="['far', 'smile-beam']" />
       </div>
       <EmojiPicker
         v-if="enableEmojiPicker"
diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js
index 3ad80df3..b1671566 100644
--- a/src/components/emoji_picker/emoji_picker.js
+++ b/src/components/emoji_picker/emoji_picker.js
@@ -1,4 +1,16 @@
 import Checkbox from '../checkbox/checkbox.vue'
+import { library } from '@fortawesome/fontawesome-svg-core'
+import {
+  faUnderline,
+  faStickyNote,
+  faSmileBeam
+} from '@fortawesome/free-solid-svg-icons'
+
+library.add(
+  faUnderline,
+  faStickyNote,
+  faSmileBeam
+)
 
 // At widest, approximately 20 emoji are visible in a row,
 // loading 3 rows, could be overkill for narrow picker
@@ -177,13 +189,13 @@ const EmojiPicker = {
         {
           id: 'custom',
           text: this.$t('emoji.custom'),
-          icon: 'icon-smile',
+          icon: 'smile-beam',
           emojis: customEmojis
         },
         {
           id: 'standard',
           text: this.$t('emoji.unicode'),
-          icon: 'icon-picture',
+          icon: 'underline',
           emojis: filterByKeyword(standardEmojis, this.keyword)
         }
       ]
diff --git a/src/components/emoji_picker/emoji_picker.scss b/src/components/emoji_picker/emoji_picker.scss
index 8bd07e45..ec711758 100644
--- a/src/components/emoji_picker/emoji_picker.scss
+++ b/src/components/emoji_picker/emoji_picker.scss
@@ -82,7 +82,7 @@
       &.active {
         border-bottom: 4px solid;
 
-        i {
+        svg {
           color: $fallback--lightText;
           color: var(--lightText, $fallback--lightText);
         }
diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
index 191b9fa1..bd093c99 100644
--- a/src/components/emoji_picker/emoji_picker.vue
+++ b/src/components/emoji_picker/emoji_picker.vue
@@ -13,7 +13,7 @@
           :title="group.text"
           @click.prevent="highlight(group.id)"
         >
-          <i :class="group.icon" />
+          <FAIcon :icon="group.icon" fixed-width/>
         </span>
       </span>
       <span
@@ -26,7 +26,7 @@
           :title="$t('emoji.stickers')"
           @click.prevent="toggleStickers"
         >
-          <i class="icon-star" />
+          <FAIcon icon="sticky-note" fixed-width/>
         </span>
       </span>
     </div>
diff --git a/src/components/extra_buttons/extra_buttons.js b/src/components/extra_buttons/extra_buttons.js
index 5e0c36bb..6892dabc 100644
--- a/src/components/extra_buttons/extra_buttons.js
+++ b/src/components/extra_buttons/extra_buttons.js
@@ -1,4 +1,8 @@
 import Popover from '../popover/popover.vue'
+import { library } from '@fortawesome/fontawesome-svg-core'
+import { faEllipsisH } from '@fortawesome/free-solid-svg-icons'
+
+library.add(faEllipsisH)
 
 const ExtraButtons = {
   props: [ 'status' ],
diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue
index 7a4e8642..0af264a5 100644
--- a/src/components/extra_buttons/extra_buttons.vue
+++ b/src/components/extra_buttons/extra_buttons.vue
@@ -73,9 +73,11 @@
         </button>
       </div>
     </div>
-    <i
+    <FAIcon
       slot="trigger"
-      class="icon-ellipsis button-icon"
+      class="button-icon"
+      icon="ellipsis-h"
+      size="lg"
     />
   </Popover>
 </template>
diff --git a/src/components/favorite_button/favorite_button.js b/src/components/favorite_button/favorite_button.js
index 5014d84f..2a2ee84a 100644
--- a/src/components/favorite_button/favorite_button.js
+++ b/src/components/favorite_button/favorite_button.js
@@ -1,4 +1,14 @@
 import { mapGetters } from 'vuex'
+import { library } from '@fortawesome/fontawesome-svg-core'
+import { faStar } from '@fortawesome/free-solid-svg-icons'
+import {
+  faStar as faStarRegular
+} from '@fortawesome/free-regular-svg-icons'
+
+library.add(
+  faStar,
+  faStarRegular
+)
 
 const FavoriteButton = {
   props: ['status', 'loggedIn'],
@@ -23,9 +33,7 @@ const FavoriteButton = {
   computed: {
     classes () {
       return {
-        'icon-star-empty': !this.status.favorited,
-        'icon-star': this.status.favorited,
-        'animate-spin': this.animated
+        '-favorited': this.status.favorited
       }
     },
     ...mapGetters(['mergedConfig'])
diff --git a/src/components/favorite_button/favorite_button.vue b/src/components/favorite_button/favorite_button.vue
index fbc90f84..6c7bfdab 100644
--- a/src/components/favorite_button/favorite_button.vue
+++ b/src/components/favorite_button/favorite_button.vue
@@ -1,18 +1,23 @@
 <template>
   <div v-if="loggedIn">
-    <i
+    <FAIcon
       :class="classes"
-      class="button-icon favorite-button fav-active"
+      class="FavoriteButton button-icon -interactive"
       :title="$t('tool_tip.favorite')"
+      :icon="[status.favorited ? 'fas' : 'far', 'star']"
+      :spin="animated"
+      size="lg"
       @click.prevent="favorite()"
     />
     <span v-if="!mergedConfig.hidePostStats && status.fave_num > 0">{{ status.fave_num }}</span>
   </div>
   <div v-else>
-    <i
+    <FAIcon
       :class="classes"
-      class="button-icon favorite-button"
+      class="FavoriteButton button-icon"
       :title="$t('tool_tip.favorite')"
+      :icon="['far', 'star']"
+      size="lg"
     />
     <span v-if="!mergedConfig.hidePostStats && status.fave_num > 0">{{ status.fave_num }}</span>
   </div>
@@ -23,18 +28,20 @@
 <style lang="scss">
 @import '../../_variables.scss';
 
-.fav-active {
-  cursor: pointer;
-  animation-duration: 0.6s;
+.FavoriteButton {
+  &.-interactive {
+    cursor: pointer;
+    animation-duration: 0.6s;
 
-  &:hover {
+    &:hover {
+      color: $fallback--cOrange;
+      color: var(--cOrange, $fallback--cOrange);
+    }
+  }
+
+  &.-favorited {
     color: $fallback--cOrange;
     color: var(--cOrange, $fallback--cOrange);
   }
 }
-
-.favorite-button.icon-star {
-  color: $fallback--cOrange;
-  color: var(--cOrange, $fallback--cOrange);
-}
 </style>
diff --git a/src/components/media_upload/media_upload.js b/src/components/media_upload/media_upload.js
index 7b8a76cc..669d8190 100644
--- a/src/components/media_upload/media_upload.js
+++ b/src/components/media_upload/media_upload.js
@@ -2,6 +2,14 @@
 import statusPosterService from '../../services/status_poster/status_poster.service.js'
 import fileSizeFormatService from '../../services/file_size_format/file_size_format.js'
 
+import { library } from '@fortawesome/fontawesome-svg-core'
+import { faUpload, faCircleNotch } from '@fortawesome/free-solid-svg-icons'
+
+library.add(
+  faUpload,
+  faCircleNotch
+)
+
 const mediaUpload = {
   data () {
     return {
diff --git a/src/components/media_upload/media_upload.vue b/src/components/media_upload/media_upload.vue
index c8865d77..38e00702 100644
--- a/src/components/media_upload/media_upload.vue
+++ b/src/components/media_upload/media_upload.vue
@@ -7,13 +7,15 @@
       class="label"
       :title="$t('tool_tip.media_upload')"
     >
-      <i
+      <FAIcon
         v-if="uploading"
-        class="progress-icon icon-spin4 animate-spin"
+        class="progress-icon animate-spin"
+        icon="circle-notch"
       />
-      <i
+      <FAIcon
         v-if="!uploading"
-        class="new-icon icon-upload"
+        class="new-icon"
+        icon="upload"
       />
       <input
         v-if="uploadReady"
diff --git a/src/components/nav_panel/nav_panel.js b/src/components/nav_panel/nav_panel.js
index 623dfaec..87e54133 100644
--- a/src/components/nav_panel/nav_panel.js
+++ b/src/components/nav_panel/nav_panel.js
@@ -1,6 +1,29 @@
 import { timelineNames } from '../timeline_menu/timeline_menu.js'
 import { mapState, mapGetters } from 'vuex'
 
+import { library } from '@fortawesome/fontawesome-svg-core'
+import {
+  faUsers,
+  faGlobeEurope,
+  faBookmark,
+  faEnvelope,
+  faHome,
+  faComments,
+  faBell,
+  faInfoCircle
+} from '@fortawesome/free-solid-svg-icons'
+
+library.add(
+  faUsers,
+  faGlobeEurope,
+  faBookmark,
+  faEnvelope,
+  faHome,
+  faComments,
+  faBell,
+  faInfoCircle
+)
+
 const NavPanel = {
   created () {
     if (this.currentUser && this.currentUser.locked) {
diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue
index 4f944c95..f3e131ff 100644
--- a/src/components/nav_panel/nav_panel.vue
+++ b/src/components/nav_panel/nav_panel.vue
@@ -1,5 +1,5 @@
 <template>
-  <div class="nav-panel">
+  <div class="NavPanel">
     <div class="panel panel-default">
       <ul>
         <li v-if="currentUser || !privateMode">
@@ -7,12 +7,14 @@
             :to="{ name: timelinesRoute }"
             :class="onTimelineRoute && 'router-link-active'"
           >
-            <i class="button-icon icon-home-2" />{{ $t("nav.timelines") }}
+            <FAIcon fixed-width size="lg" class="button-icon" icon="home" />
+            {{ $t("nav.timelines") }}
           </router-link>
         </li>
         <li v-if="currentUser">
           <router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }">
-            <i class="button-icon icon-bell-alt" />{{ $t("nav.interactions") }}
+            <FAIcon fixed-width size="lg" class="button-icon" icon="bell" />
+            {{ $t("nav.interactions") }}
           </router-link>
         </li>
         <li v-if="currentUser && pleromaChatMessagesAvailable">
@@ -23,12 +25,14 @@
             >
               {{ unreadChatCount }}
             </div>
-            <i class="button-icon icon-chat" />{{ $t("nav.chats") }}
+            <FAIcon fixed-width size="lg" class="button-icon" icon="comments" />
+            {{ $t("nav.chats") }}
           </router-link>
         </li>
         <li v-if="currentUser && currentUser.locked">
           <router-link :to="{ name: 'friend-requests' }">
-            <i class="button-icon icon-user-plus" />{{ $t("nav.friend_requests") }}
+            <FAIcon fixed-width size="lg" class="button-icon" icon="user-plus" />
+            {{ $t("nav.friend_requests") }}
             <span
               v-if="followRequestCount > 0"
               class="badge follow-request-count"
@@ -39,7 +43,7 @@
         </li>
         <li>
           <router-link :to="{ name: 'about' }">
-            <i class="button-icon icon-info-circled" />{{ $t("nav.about") }}
+            <FAIcon fixed-width size="lg" class="button-icon" icon="info-circle" />{{ $t("nav.about") }}
           </router-link>
         </li>
       </ul>
@@ -52,84 +56,88 @@
 <style lang="scss">
 @import '../../_variables.scss';
 
-.nav-panel .panel {
-  overflow: hidden;
-  box-shadow: var(--panelShadow);
-}
-.nav-panel ul {
-  list-style: none;
-  margin: 0;
-  padding: 0;
-}
-
-.follow-request-count {
-  margin: -6px 10px;
-  background-color: $fallback--bg;
-  background-color: var(--input, $fallback--faint);
-}
-
-.nav-panel li {
-  border-bottom: 1px solid;
-  border-color: $fallback--border;
-  border-color: var(--border, $fallback--border);
-  padding: 0;
-
-  &:first-child a {
-    border-top-right-radius: $fallback--panelRadius;
-    border-top-right-radius: var(--panelRadius, $fallback--panelRadius);
-    border-top-left-radius: $fallback--panelRadius;
-    border-top-left-radius: var(--panelRadius, $fallback--panelRadius);
+.NavPanel {
+  .panel {
+    overflow: hidden;
+    box-shadow: var(--panelShadow);
   }
 
-  &:last-child a {
-    border-bottom-right-radius: $fallback--panelRadius;
-    border-bottom-right-radius: var(--panelRadius, $fallback--panelRadius);
-    border-bottom-left-radius: $fallback--panelRadius;
-    border-bottom-left-radius: var(--panelRadius, $fallback--panelRadius);
-  }
-}
-
-.nav-panel li:last-child {
-  border: none;
-}
-
-.nav-panel a {
-  display: block;
-  padding: 0.8em 0.85em;
-
-  &:hover {
-    background-color: $fallback--lightBg;
-    background-color: var(--selectedMenu, $fallback--lightBg);
-    color: $fallback--link;
-    color: var(--selectedMenuText, $fallback--link);
-    --faint: var(--selectedMenuFaintText, $fallback--faint);
-    --faintLink: var(--selectedMenuFaintLink, $fallback--faint);
-    --lightText: var(--selectedMenuLightText, $fallback--lightText);
-    --icon: var(--selectedMenuIcon, $fallback--icon);
+  ul {
+    list-style: none;
+    margin: 0;
+    padding: 0;
   }
 
-  &.router-link-active {
-    font-weight: bolder;
-    background-color: $fallback--lightBg;
-    background-color: var(--selectedMenu, $fallback--lightBg);
-    color: $fallback--text;
-    color: var(--selectedMenuText, $fallback--text);
-    --faint: var(--selectedMenuFaintText, $fallback--faint);
-    --faintLink: var(--selectedMenuFaintLink, $fallback--faint);
-    --lightText: var(--selectedMenuLightText, $fallback--lightText);
-    --icon: var(--selectedMenuIcon, $fallback--icon);
+  .follow-request-count {
+    margin: -6px 10px;
+    background-color: $fallback--bg;
+    background-color: var(--input, $fallback--faint);
+  }
 
-    &:hover {
-      text-decoration: underline;
+  li {
+    border-bottom: 1px solid;
+    border-color: $fallback--border;
+    border-color: var(--border, $fallback--border);
+    padding: 0;
+
+    &:first-child a {
+      border-top-right-radius: $fallback--panelRadius;
+      border-top-right-radius: var(--panelRadius, $fallback--panelRadius);
+      border-top-left-radius: $fallback--panelRadius;
+      border-top-left-radius: var(--panelRadius, $fallback--panelRadius);
+    }
+
+    &:last-child a {
+      border-bottom-right-radius: $fallback--panelRadius;
+      border-bottom-right-radius: var(--panelRadius, $fallback--panelRadius);
+      border-bottom-left-radius: $fallback--panelRadius;
+      border-bottom-left-radius: var(--panelRadius, $fallback--panelRadius);
     }
   }
-}
 
-.nav-panel .button-icon {
-  margin-right: 0.5em;
-}
+  li:last-child {
+    border: none;
+  }
 
-.nav-panel .button-icon:before {
-  width: 1.1em;
+  a {
+    display: block;
+    padding: 0.8em 0.85em;
+
+    &:hover {
+      background-color: $fallback--lightBg;
+      background-color: var(--selectedMenu, $fallback--lightBg);
+      color: $fallback--link;
+      color: var(--selectedMenuText, $fallback--link);
+      --faint: var(--selectedMenuFaintText, $fallback--faint);
+      --faintLink: var(--selectedMenuFaintLink, $fallback--faint);
+      --lightText: var(--selectedMenuLightText, $fallback--lightText);
+      --icon: var(--selectedMenuIcon, $fallback--icon);
+    }
+
+    &.router-link-active {
+      font-weight: bolder;
+      background-color: $fallback--lightBg;
+      background-color: var(--selectedMenu, $fallback--lightBg);
+      color: $fallback--text;
+      color: var(--selectedMenuText, $fallback--text);
+      --faint: var(--selectedMenuFaintText, $fallback--faint);
+      --faintLink: var(--selectedMenuFaintLink, $fallback--faint);
+      --lightText: var(--selectedMenuLightText, $fallback--lightText);
+      --icon: var(--selectedMenuIcon, $fallback--icon);
+
+      &:hover {
+        text-decoration: underline;
+      }
+    }
+  }
+
+  .button-icon {
+    margin-left: -0.1em;
+    margin-right: 0.2em;
+  }
+
+  .button-icon:before {
+    width: 1.1em;
+  }
 }
 </style>
diff --git a/src/components/poll/poll_form.js b/src/components/poll/poll_form.js
index df93f038..1f8df3f9 100644
--- a/src/components/poll/poll_form.js
+++ b/src/components/poll/poll_form.js
@@ -1,5 +1,17 @@
 import * as DateUtils from 'src/services/date_utils/date_utils.js'
 import { uniq } from 'lodash'
+import { library } from '@fortawesome/fontawesome-svg-core'
+import {
+  faTimes,
+  faChevronDown,
+  faPlus
+} from '@fortawesome/free-solid-svg-icons'
+
+library.add(
+  faTimes,
+  faChevronDown,
+  faPlus
+)
 
 export default {
   name: 'PollForm',
diff --git a/src/components/poll/poll_form.vue b/src/components/poll/poll_form.vue
index d53f3837..3a8a2f42 100644
--- a/src/components/poll/poll_form.vue
+++ b/src/components/poll/poll_form.vue
@@ -24,8 +24,8 @@
         v-if="options.length > 2"
         class="icon-container"
       >
-        <i
-          class="icon-cancel"
+        <FAIcon
+          icon="times"
           @click="deleteOption(index)"
         />
       </div>
@@ -35,7 +35,8 @@
       class="add-option faint"
       @click="addOption"
     >
-      <i class="icon-plus" />
+      <FAIcon icon="plus" size="sm"/>
+
       {{ $t("polls.add_option") }}
     </a>
     <div class="poll-type-expiry">
@@ -55,7 +56,7 @@
             <option value="single">{{ $t('polls.single_choice') }}</option>
             <option value="multiple">{{ $t('polls.multiple_choices') }}</option>
           </select>
-          <i class="icon-down-open" />
+          <FAIcon class="icon-down-open" icon="chevron-down"/>
         </label>
       </div>
       <div
@@ -83,7 +84,7 @@
               {{ $t(`time.${unit}_short`, ['']) }}
             </option>
           </select>
-          <i class="icon-down-open" />
+          <FAIcon class="icon-down-open" icon="chevron-down"/>
         </label>
       </div>
     </div>
@@ -103,6 +104,7 @@
   .add-option {
     align-self: flex-start;
     padding-top: 0.25em;
+    padding-left: 0.1em;
     cursor: pointer;
   }
 
@@ -124,8 +126,8 @@
 
   .icon-container {
     // Hack: Move the icon over the input box
-    width: 2em;
-    margin-left: -2em;
+    width: 1.5em;
+    margin-left: -1.5em;
     z-index: 1;
   }
 
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index ad149506..1267225d 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -12,6 +12,23 @@ import suggestor from '../emoji_input/suggestor.js'
 import { mapGetters, mapState } from 'vuex'
 import Checkbox from '../checkbox/checkbox.vue'
 
+import { library } from '@fortawesome/fontawesome-svg-core'
+import {
+  faChevronDown,
+  faSmileBeam,
+  faPollH,
+  faUpload,
+  faBan
+} from '@fortawesome/free-solid-svg-icons'
+
+library.add(
+  faChevronDown,
+  faSmileBeam,
+  faPollH,
+  faUpload,
+  faBan
+)
+
 const buildMentionsString = ({ user, attentions = [] }, currentUser) => {
   let allAttentions = [...attentions]
 
diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue
index d67d9ae9..9a5be689 100644
--- a/src/components/post_status_form/post_status_form.vue
+++ b/src/components/post_status_form/post_status_form.vue
@@ -12,10 +12,11 @@
         v-show="showDropIcon !== 'hide'"
         :style="{ animation: showDropIcon === 'show' ? 'fade-in 0.25s' : 'fade-out 0.5s' }"
         class="drop-indicator"
-        :class="[uploadFileLimitReached ? 'icon-block' : 'icon-upload']"
         @dragleave="fileDragStop"
         @drop.stop="fileDrop"
-      />
+      >
+        <FAIcon :icon="uploadFileLimitReached ? 'ban' : 'upload'"/>
+      </div>
       <div class="form-group">
         <i18n
           v-if="!$store.state.users.currentUser.locked && newStatus.visibility == 'private' && !disableLockWarning"
@@ -198,7 +199,7 @@
                   {{ $t(`post_status.content_type["${postFormat}"]`) }}
                 </option>
               </select>
-              <i class="icon-down-open" />
+              <FAIcon class="icon-down-open" icon="chevron-down"/>
             </label>
           </div>
           <div
@@ -235,22 +236,22 @@
           <div
             class="emoji-icon"
           >
-            <i
+            <div
               :title="$t('emoji.add_emoji')"
-              class="icon-smile btn btn-default"
+              class="btn btn-default"
               @click="showEmojiPicker"
-            />
+            >
+              <FAIcon icon="smile-beam"/>
+            </div>
           </div>
           <div
             v-if="pollsAvailable"
             class="poll-icon"
             :class="{ selected: pollFormVisible }"
+            :title="$t('polls.add_poll')"
+            @click="togglePollForm"
           >
-            <i
-              :title="$t('polls.add_poll')"
-              class="icon-chart-bar btn btn-default"
-              @click="togglePollForm"
-            />
+            <FAIcon icon="poll-h" />
           </div>
         </div>
         <button
@@ -392,7 +393,7 @@
     &:hover {
       text-decoration: underline;
     }
-    i {
+    svg, i {
       margin-left: 0.2em;
       font-size: 0.8em;
       transform: rotate(90deg);
@@ -434,18 +435,20 @@
 
   .media-upload-icon, .poll-icon, .emoji-icon {
     font-size: 26px;
+    line-height: 1.1;
     flex: 1;
+    padding: 0 0.1em;
 
     &.selected, &:hover {
       // needs to be specific to override icon default color
-      i, label {
+      svg, i, label {
         color: $fallback--lightText;
         color: var(--lightText, $fallback--lightText);
       }
     }
 
     &.disabled {
-      i {
+      svg, i {
         cursor: not-allowed;
         color: $fallback--icon;
         color: var(--btnDisabledText, $fallback--icon);
diff --git a/src/components/react_button/react_button.js b/src/components/react_button/react_button.js
index dd71e546..de0df70c 100644
--- a/src/components/react_button/react_button.js
+++ b/src/components/react_button/react_button.js
@@ -1,4 +1,8 @@
 import Popover from '../popover/popover.vue'
+import { library } from '@fortawesome/fontawesome-svg-core'
+import { faSmileBeam } from '@fortawesome/free-regular-svg-icons'
+
+library.add(faSmileBeam)
 
 const ReactButton = {
   props: ['status'],
diff --git a/src/components/react_button/react_button.vue b/src/components/react_button/react_button.vue
index 0b34add1..8395d5e3 100644
--- a/src/components/react_button/react_button.vue
+++ b/src/components/react_button/react_button.vue
@@ -36,9 +36,11 @@
         <div class="reaction-bottom-fader" />
       </div>
     </div>
-    <i
+    <FAIcon
       slot="trigger"
-      class="icon-smile button-icon add-reaction-button"
+      class="button-icon add-reaction-button"
+      :icon="['far', 'smile-beam']"
+      size="lg"
       :title="$t('tool_tip.add_reaction')"
     />
   </Popover>
diff --git a/src/components/reply_button/reply_button.js b/src/components/reply_button/reply_button.js
index 22957650..c7bd2a2b 100644
--- a/src/components/reply_button/reply_button.js
+++ b/src/components/reply_button/reply_button.js
@@ -1,3 +1,7 @@
+import { library } from '@fortawesome/fontawesome-svg-core'
+import { faReply } from '@fortawesome/free-solid-svg-icons'
+
+library.add(faReply)
 
 const ReplyButton = {
   name: 'ReplyButton',
diff --git a/src/components/reply_button/reply_button.vue b/src/components/reply_button/reply_button.vue
index b2904b5c..ae7b0e26 100644
--- a/src/components/reply_button/reply_button.vue
+++ b/src/components/reply_button/reply_button.vue
@@ -1,15 +1,19 @@
 <template>
   <div>
-    <i
+    <FAIcon
       v-if="loggedIn"
-      class="button-icon button-reply icon-reply"
+      class="ReplyButton button-icon -interactive"
+      icon="reply"
+      size="lg"
       :title="$t('tool_tip.reply')"
       :class="{'-active': replying}"
       @click.prevent="$emit('toggle')"
     />
-    <i
+    <FAIcon
       v-else
-      class="button-icon button-reply -disabled icon-reply"
+      icon="reply"
+      size="lg"
+      class="ReplyButton button-icon"
       :title="$t('tool_tip.reply')"
     />
     <span v-if="status.replies_count > 0">
@@ -19,3 +23,19 @@
 </template>
 
 <script src="./reply_button.js"></script>
+
+<style lang="scss">
+@import '../../_variables.scss';
+
+.ReplyButton {
+  &.-interactive {
+    cursor: pointer;
+
+    &:hover,
+    &.-active {
+      color: $fallback--cBlue;
+      color: var(--cBlue, $fallback--cBlue);
+    }
+  }
+}
+</style>
diff --git a/src/components/retweet_button/retweet_button.js b/src/components/retweet_button/retweet_button.js
index 5a41f22d..5ee4179a 100644
--- a/src/components/retweet_button/retweet_button.js
+++ b/src/components/retweet_button/retweet_button.js
@@ -1,3 +1,7 @@
+import { library } from '@fortawesome/fontawesome-svg-core'
+import { faRetweet } from '@fortawesome/free-solid-svg-icons'
+
+library.add(faRetweet)
 
 const RetweetButton = {
   props: ['status', 'loggedIn', 'visibility'],
@@ -22,9 +26,7 @@ const RetweetButton = {
   computed: {
     classes () {
       return {
-        'retweeted': this.status.repeated,
-        'retweeted-empty': !this.status.repeated,
-        'animate-spin': this.animated
+        '-repeated': this.status.repeated
       }
     },
     mergedConfig () {
diff --git a/src/components/retweet_button/retweet_button.vue b/src/components/retweet_button/retweet_button.vue
index 074f7747..3e15f30b 100644
--- a/src/components/retweet_button/retweet_button.vue
+++ b/src/components/retweet_button/retweet_button.vue
@@ -1,26 +1,33 @@
 <template>
   <div v-if="loggedIn">
     <template v-if="visibility !== 'private' && visibility !== 'direct'">
-      <i
-        :class="classes"
-        class="button-icon retweet-button icon-retweet rt-active"
-        :title="$t('tool_tip.repeat')"
-        @click.prevent="retweet()"
-      />
+    <FAIcon
+      :class="classes"
+      class="RetweetButton button-icon -interactive"
+      icon="retweet"
+      size="lg"
+      :spin="animated"
+      :title="$t('tool_tip.repeat')"
+      @click.prevent="retweet()"
+    />
       <span v-if="!mergedConfig.hidePostStats && status.repeat_num > 0">{{ status.repeat_num }}</span>
     </template>
     <template v-else>
-      <i
+      <FAIcon
         :class="classes"
-        class="button-icon icon-lock"
+        class="RetweetButton button-icon"
+        icon="lock"
+        size="lg"
         :title="$t('timeline.no_retweet_hint')"
       />
     </template>
   </div>
   <div v-else-if="!loggedIn">
-    <i
+    <FAIcon
       :class="classes"
-      class="button-icon icon-retweet"
+      class="button-icon"
+      icon="retweet"
+      size="lg"
       :title="$t('tool_tip.repeat')"
     />
     <span v-if="!mergedConfig.hidePostStats && status.repeat_num > 0">{{ status.repeat_num }}</span>
@@ -31,16 +38,21 @@
 
 <style lang="scss">
 @import '../../_variables.scss';
-.rt-active {
-  cursor: pointer;
-  animation-duration: 0.6s;
-  &:hover {
+
+.RetweetButton {
+  &.-interactive {
+    cursor: pointer;
+    animation-duration: 0.6s;
+
+    &:hover {
+      color: $fallback--cGreen;
+      color: var(--cGreen, $fallback--cGreen);
+    }
+  }
+
+  &.-repeated {
     color: $fallback--cGreen;
     color: var(--cGreen, $fallback--cGreen);
   }
 }
-.icon-retweet.retweeted {
-  color: $fallback--cGreen;
-  color: var(--cGreen, $fallback--cGreen);
-}
 </style>
diff --git a/src/components/scope_selector/scope_selector.js b/src/components/scope_selector/scope_selector.js
index e9ccdefc..34efdc00 100644
--- a/src/components/scope_selector/scope_selector.js
+++ b/src/components/scope_selector/scope_selector.js
@@ -1,3 +1,18 @@
+import { library } from '@fortawesome/fontawesome-svg-core'
+import {
+  faEnvelope,
+  faLock,
+  faLockOpen,
+  faGlobeEurope
+} from '@fortawesome/free-solid-svg-icons'
+
+library.add(
+  faEnvelope,
+  faGlobeEurope,
+  faLock,
+  faLockOpen
+)
+
 const ScopeSelector = {
   props: [
     'showAll',
diff --git a/src/components/scope_selector/scope_selector.vue b/src/components/scope_selector/scope_selector.vue
index 291236f2..5b9abd64 100644
--- a/src/components/scope_selector/scope_selector.vue
+++ b/src/components/scope_selector/scope_selector.vue
@@ -1,36 +1,44 @@
 <template>
   <div
     v-if="!showNothing"
-    class="scope-selector"
-  >
-    <i
+    class="ScopeSelector"
+    >
+    <span
       v-if="showDirect"
-      class="icon-mail-alt"
+      class="scope"
       :class="css.direct"
       :title="$t('post_status.scope.direct')"
       @click="changeVis('direct')"
-    />
-    <i
+      >
+      <FAIcon icon="envelope" class="button-icon" size="lg" />
+    </span>
+    <span
+      class="scope"
       v-if="showPrivate"
-      class="icon-lock"
       :class="css.private"
       :title="$t('post_status.scope.private')"
       @click="changeVis('private')"
-    />
-    <i
+      >
+      <FAIcon icon="lock" class="button-icon" size="lg" />
+    </span>
+    <span
       v-if="showUnlisted"
-      class="icon-lock-open-alt"
+      class="scope"
       :class="css.unlisted"
       :title="$t('post_status.scope.unlisted')"
       @click="changeVis('unlisted')"
-    />
-    <i
+      >
+      <FAIcon icon="lock-open" class="button-icon" size="lg" />
+    </span>
+    <span
       v-if="showPublic"
-      class="icon-globe"
+      class="scope"
       :class="css.public"
       :title="$t('post_status.scope.public')"
       @click="changeVis('public')"
-    />
+      >
+      <FAIcon icon="globe-europe" class="button-icon" size="lg" />
+    </span>
   </div>
 </template>
 
@@ -39,12 +47,16 @@
 <style lang="scss">
 @import '../../_variables.scss';
 
-.scope-selector {
-  i {
-    font-size: 1.2em;
-    cursor: pointer;
+.ScopeSelector {
 
-    &.selected {
+  .scope {
+    display: inline-block;
+    cursor: pointer;
+    min-width: 1.3em;
+    min-height: 1.3em;
+    text-align: center;
+
+    &.selected svg {
       color: $fallback--lightText;
       color: var(--lightText, $fallback--lightText);
     }
diff --git a/src/components/status/status.js b/src/components/status/status.js
index e48b2eb8..f7a0ff83 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -17,6 +17,47 @@ import { highlightClass, highlightStyle } from '../../services/user_highlighter/
 import { muteWordHits } from '../../services/status_parser/status_parser.js'
 import { unescape, uniqBy } from 'lodash'
 
+import { library } from '@fortawesome/fontawesome-svg-core'
+import {
+  faEnvelope,
+  faLock,
+  faLockOpen,
+  faGlobeEurope,
+  faTimes,
+  faRetweet,
+  faReply,
+  faExternalLinkSquareAlt,
+  faPlusSquare,
+  faSmileBeam,
+  faEllipsisH,
+  faStar,
+  faEyeSlash,
+  faEye,
+  faThumbtack
+} from '@fortawesome/free-solid-svg-icons'
+import {
+  faStar as faStarRegular
+} from '@fortawesome/free-regular-svg-icons'
+
+library.add(
+  faEnvelope,
+  faGlobeEurope,
+  faLock,
+  faLockOpen,
+  faTimes,
+  faRetweet,
+  faReply,
+  faExternalLinkSquareAlt,
+  faPlusSquare,
+  faStar,
+  faStarRegular,
+  faSmileBeam,
+  faEllipsisH,
+  faEyeSlash,
+  faEye,
+  faThumbtack
+)
+
 const Status = {
   name: 'Status',
   components: {
@@ -227,13 +268,13 @@ const Status = {
     visibilityIcon (visibility) {
       switch (visibility) {
         case 'private':
-          return 'icon-lock'
+          return 'lock'
         case 'unlisted':
-          return 'icon-lock-open-alt'
+          return 'lock-open'
         case 'direct':
-          return 'icon-mail-alt'
+          return 'envelope'
         default:
-          return 'icon-globe'
+          return 'globe-europe'
       }
     },
     showError (error) {
diff --git a/src/components/status/status.scss b/src/components/status/status.scss
index 66a91c1e..cd5366ed 100644
--- a/src/components/status/status.scss
+++ b/src/components/status/status.scss
@@ -200,7 +200,6 @@ $status-margin: 0.75em;
   }
 
   .reply-to {
-    display: flex;
     position: relative;
   }
 
@@ -208,7 +207,6 @@ $status-margin: 0.75em;
     overflow: hidden;
     text-overflow: ellipsis;
     white-space: nowrap;
-    margin-left: 0.2em;
   }
 
   .replies-separator {
@@ -232,16 +230,10 @@ $status-margin: 0.75em;
 
   .repeat-info {
     padding: 0.4em $status-margin;
-    line-height: 22px;
 
-    .right-side {
-      display: flex;
-      align-content: center;
-      flex-wrap: wrap;
-    }
-
-    i {
-      padding: 0 0.2em;
+    .repeat-icon {
+      color: $fallback--cGreen;
+      color: var(--cGreen, $fallback--cGreen);
     }
   }
 
@@ -291,18 +283,6 @@ $status-margin: 0.75em;
     }
   }
 
-  .button-reply {
-    &:not(.-disabled) {
-      cursor: pointer;
-    }
-
-    &:not(.-disabled):hover,
-    &.-active {
-      color: $fallback--cBlue;
-      color: var(--cBlue, $fallback--cBlue);
-    }
-  }
-
   .muted {
     padding: 0.25em 0.6em;
     height: 1.2em;
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index ffae32fc..b9b967cc 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -10,17 +10,20 @@
       class="alert error"
     >
       {{ error }}
-      <i
-        class="button-icon icon-cancel"
+      <span
+        class="button-icon"
         @click="clearError"
-      />
+        >
+        <FAIcon icon="times" />
+      </span>
     </div>
     <template v-if="muted && !isPreview">
       <div class="status-container muted">
         <small class="status-username">
-          <i
+          <FAIcon
             v-if="muted && retweet"
-            class="button-icon icon-retweet"
+            class="button-icon repeat-icon"
+            icon="retweet"
           />
           <router-link :to="userProfileLink">
             {{ status.user.screen_name }}
@@ -46,9 +49,11 @@
         </small>
         <a
           href="#"
-          class="unmute"
+          class="unmute button-icon"
           @click.prevent="toggleMute"
-        ><i class="button-icon icon-eye-off" /></a>
+          >
+          <FAIcon icon="eye-slash" class="button-icon" size="lg" />
+        </a>
       </div>
     </template>
     <template v-else>
@@ -56,7 +61,7 @@
         v-if="showPinned"
         class="pin"
       >
-        <i class="fa icon-pin faint" />
+        <FAIcon icon="thumbtack" class="faint" />
         <span class="faint">{{ $t('status.pinned') }}</span>
       </div>
       <div
@@ -86,8 +91,9 @@
               :to="retweeterProfileLink"
             >{{ retweeter }}</router-link>
           </span>
-          <i
-            class="fa icon-retweet retweeted"
+          <FAIcon
+            icon="retweet"
+            class="repeat-icon"
             :title="$t('tool_tip.repeat')"
           />
           {{ $t('timeline.repeated') }}
@@ -167,15 +173,13 @@
                     :auto-update="60"
                   />
                 </router-link>
-                <div
+                <span
                   v-if="status.visibility"
-                  class="button-icon visibility-icon"
-                >
-                  <i
-                    :class="visibilityIcon(status.visibility)"
-                    :title="status.visibility | capitalize"
-                  />
-                </div>
+                  class="visibility-icon"
+                  :title="status.visibility | capitalize"
+                  >
+                  <FAIcon class="button-icon" :icon="visibilityIcon(status.visibility)" size="lg" />
+                </span>
                 <a
                   v-if="!status.is_local && !isPreview"
                   :href="status.external_url"
@@ -183,22 +187,23 @@
                   class="source_url"
                   title="Source"
                 >
-                  <i class="button-icon icon-link-ext-alt" />
+                  <FAIcon class="button-icon" icon="external-link-square-alt" size="lg" />
+                </a>
+                <a
+                  v-if="expandable && !isPreview"
+                  href="#"
+                  title="Expand"
+                  @click.prevent="toggleExpanded"
+                >
+                  <FAIcon class="button-icon" icon="plus-square" size="lg" />
                 </a>
-                <template v-if="expandable && !isPreview">
-                  <a
-                    href="#"
-                    title="Expand"
-                    @click.prevent="toggleExpanded"
-                  >
-                    <i class="button-icon icon-plus-squared" />
-                  </a>
-                </template>
                 <a
                   v-if="unmuted"
                   href="#"
                   @click.prevent="toggleMute"
-                ><i class="button-icon icon-eye-off" /></a>
+                >
+                  <FAIcon icon="eye-slash" class="button-icon" size="lg" />
+                </a>
               </span>
             </div>
 
@@ -220,7 +225,12 @@
                     :aria-label="$t('tool_tip.reply')"
                     @click.prevent="gotoOriginal(status.in_reply_to_status_id)"
                   >
-                    <i class="button-icon reply-button icon-reply" />
+                    <FAIcon
+                      class="button-icon"
+                      icon="reply"
+                      size="lg"
+                      flip="horizontal"
+                      />
                     <span
                       class="faint-link reply-to-text"
                     >
diff --git a/src/components/timeline_menu/timeline_menu.js b/src/components/timeline_menu/timeline_menu.js
index 2be75b06..991c600d 100644
--- a/src/components/timeline_menu/timeline_menu.js
+++ b/src/components/timeline_menu/timeline_menu.js
@@ -1,5 +1,23 @@
 import Popover from '../popover/popover.vue'
 import { mapState } from 'vuex'
+import { library } from '@fortawesome/fontawesome-svg-core'
+import {
+  faUsers,
+  faGlobeEurope,
+  faBookmark,
+  faEnvelope,
+  faHome,
+  faChevronDown
+} from '@fortawesome/free-solid-svg-icons'
+
+library.add(
+  faUsers,
+  faGlobeEurope,
+  faBookmark,
+  faEnvelope,
+  faHome,
+  faChevronDown
+)
 
 // Route -> i18n key mapping, exported andnot in the computed
 // because nav panel benefits from the same information.
diff --git a/src/components/timeline_menu/timeline_menu.vue b/src/components/timeline_menu/timeline_menu.vue
index b7e5f2da..590752d3 100644
--- a/src/components/timeline_menu/timeline_menu.vue
+++ b/src/components/timeline_menu/timeline_menu.vue
@@ -1,7 +1,7 @@
 <template>
   <Popover
     trigger="click"
-    class="timeline-menu"
+    class="TimelineMenu"
     :class="{ 'open': isOpen }"
     :margin="{ left: -15, right: -200 }"
     :bound-to="{ x: 'container' }"
@@ -16,27 +16,27 @@
       <ul>
         <li v-if="currentUser">
           <router-link :to="{ name: 'friends' }">
-            <i class="button-icon icon-home-2" />{{ $t("nav.timeline") }}
+            <FAIcon fixed-width size="lg" class="button-icon " icon="home" />{{ $t("nav.timeline") }}
           </router-link>
         </li>
         <li v-if="currentUser">
           <router-link :to="{ name: 'bookmarks'}">
-            <i class="button-icon icon-bookmark" />{{ $t("nav.bookmarks") }}
+            <FAIcon fixed-width size="lg" class="button-icon " icon="bookmark" />{{ $t("nav.bookmarks") }}
           </router-link>
         </li>
         <li v-if="currentUser">
           <router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
-            <i class="button-icon icon-mail-alt" />{{ $t("nav.dms") }}
+            <FAIcon fixed-width size="lg" class="button-icon " icon="envelope" />{{ $t("nav.dms") }}
           </router-link>
         </li>
         <li v-if="currentUser || !privateMode">
           <router-link :to="{ name: 'public-timeline' }">
-            <i class="button-icon icon-users" />{{ $t("nav.public_tl") }}
+            <FAIcon fixed-width size="lg" class="button-icon " icon="users" />{{ $t("nav.public_tl") }}
           </router-link>
         </li>
         <li v-if="federating && (currentUser || !privateMode)">
           <router-link :to="{ name: 'public-external-timeline' }">
-            <i class="button-icon icon-globe" />{{ $t("nav.twkn") }}
+            <FAIcon fixed-width size="lg" class="button-icon " icon="globe-europe" />{{ $t("nav.twkn") }}
           </router-link>
         </li>
       </ul>
@@ -46,7 +46,7 @@
       class="title timeline-menu-title"
     >
       <span>{{ timelineName() }}</span>
-      <i class="icon-down-open" />
+      <FAIcon size="sm" icon="chevron-down" />
     </div>
   </Popover>
 </template>
@@ -56,17 +56,19 @@
 <style lang="scss">
 @import '../../_variables.scss';
 
-.timeline-menu {
+.TimelineMenu {
   flex-shrink: 1;
   margin-right: auto;
   min-width: 0;
   width: 24rem;
+
   .timeline-menu-popover-wrap {
     overflow: hidden;
     // Match panel heading padding to line up menu with bottom of heading
     margin-top: 0.6rem;
     padding: 0 15px 15px 15px;
   }
+
   .timeline-menu-popover {
     width: 24rem;
     max-width: 100vw;
@@ -77,10 +79,12 @@
     transform: translateY(-100%);
     transition: transform 100ms;
   }
+
   .panel::after {
     border-top-right-radius: 0;
     border-top-left-radius: 0;
   }
+
   &.open .timeline-menu-popover {
     transform: translateY(0);
   }
@@ -88,7 +92,6 @@
   .timeline-menu-title {
     margin: 0;
     cursor: pointer;
-    display: flex;
     user-select: none;
     width: 100%;
 
@@ -98,15 +101,13 @@
       white-space: nowrap;
     }
 
-    i {
+    svg {
       margin-left: 0.6em;
-      flex-shrink: 0;
-      font-size: 1rem;
       transition: transform 100ms;
     }
   }
 
-  &.open .timeline-menu-title i {
+  &.open .timeline-menu-title svg {
     color: $fallback--text;
     color: var(--panelText, $fallback--text);
     transform: rotate(180deg);
@@ -171,8 +172,9 @@
       }
     }
 
-    i {
-      margin-right: 0.5em;
+    svg {
+      margin-right: 0.4em;
+      margin-left: -0.2em;
     }
   }
 }
diff --git a/src/main.js b/src/main.js
index 0a898022..42b6bcb2 100644
--- a/src/main.js
+++ b/src/main.js
@@ -33,6 +33,8 @@ import VueClickOutside from 'v-click-outside'
 import PortalVue from 'portal-vue'
 import VBodyScrollLock from './directives/body_scroll_lock'
 
+import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
+
 import afterStoreSetup from './boot/after_store.js'
 
 const currentLocale = (window.navigator.language || 'en').split('-')[0]
@@ -45,6 +47,8 @@ Vue.use(VueClickOutside)
 Vue.use(PortalVue)
 Vue.use(VBodyScrollLock)
 
+Vue.component('FAIcon', FontAwesomeIcon)
+
 const i18n = new VueI18n({
   // By default, use the browser locale, we will update it if neccessary
   locale: 'en',
diff --git a/yarn.lock b/yarn.lock
index 14be84a6..e7ba92e4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -884,6 +884,37 @@
   dependencies:
     qrcode "^1.3.0"
 
+"@fortawesome/fontawesome-common-types@^0.2.32":
+  version "0.2.32"
+  resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.32.tgz#3436795d5684f22742989bfa08f46f50f516f259"
+  integrity sha512-ux2EDjKMpcdHBVLi/eWZynnPxs0BtFVXJkgHIxXRl+9ZFaHPvYamAfCzeeQFqHRjuJtX90wVnMRaMQAAlctz3w==
+
+"@fortawesome/fontawesome-svg-core@^1.2.32":
+  version "1.2.32"
+  resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.32.tgz#da092bfc7266aa274be8604de610d7115f9ba6cf"
+  integrity sha512-XjqyeLCsR/c/usUpdWcOdVtWFVjPbDFBTQkn2fQRrWhhUoxriQohO2RWDxLyUM8XpD+Zzg5xwJ8gqTYGDLeGaQ==
+  dependencies:
+    "@fortawesome/fontawesome-common-types" "^0.2.32"
+
+"@fortawesome/free-regular-svg-icons@^5.15.1":
+  version "5.15.1"
+  resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.1.tgz#a8897d0ce325352dbba0e943101323e0175ee2b2"
+  integrity sha512-eD9NWFy89e7SVVtrLedJUxIpCBGhd4x7s7dhesokjyo1Tw62daqN5UcuAGu1NrepLLq1IeAYUVfWwnOjZ/j3HA==
+  dependencies:
+    "@fortawesome/fontawesome-common-types" "^0.2.32"
+
+"@fortawesome/free-solid-svg-icons@^5.15.1":
+  version "5.15.1"
+  resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.1.tgz#e1432676ddd43108b41197fee9f86d910ad458ef"
+  integrity sha512-EFMuKtzRMNbvjab/SvJBaOOpaqJfdSap/Nl6hst7CgrJxwfORR1drdTV6q1Ib/JVzq4xObdTDcT6sqTaXMqfdg==
+  dependencies:
+    "@fortawesome/fontawesome-common-types" "^0.2.32"
+
+"@fortawesome/vue-fontawesome@^2.0.0":
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/@fortawesome/vue-fontawesome/-/vue-fontawesome-2.0.0.tgz#63da3e459147cebb0a8d58eed81d6071db9f5973"
+  integrity sha512-N3VKw7KzRfOm8hShUVldpinlm13HpvLBQgT63QS+aCrIRLwjoEUXY5Rcmttbfb6HkzZaeqjLqd/aZCQ53UjQpg==
+
 "@nodelib/fs.scandir@2.1.3":
   version "2.1.3"
   resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b"