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"