Some initial work on replacing icons with FA5

This commit is contained in:
Henry Jameson 2020-10-19 19:38:49 +03:00
parent 350f25016f
commit 3814218277
34 changed files with 528 additions and 245 deletions

View file

@ -18,6 +18,10 @@
"dependencies": { "dependencies": {
"@babel/runtime": "^7.7.6", "@babel/runtime": "^7.7.6",
"@chenfengyuan/vue-qrcode": "^1.0.0", "@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", "body-scroll-lock": "^2.6.4",
"chromatism": "^3.0.0", "chromatism": "^3.0.0",
"cropperjs": "^1.4.3", "cropperjs": "^1.4.3",

View file

@ -318,7 +318,7 @@ option {
} }
} }
i[class*=icon-] { i[class*=icon-], .svg-inline--fa {
color: $fallback--icon; color: $fallback--icon;
color: var(--icon, $fallback--icon); color: var(--icon, $fallback--icon);
} }
@ -808,7 +808,12 @@ nav {
} }
.button-icon { .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 { @keyframes shakeError {

View file

@ -3,6 +3,15 @@ import EmojiPicker from '../emoji_picker/emoji_picker.vue'
import { take } from 'lodash' import { take } from 'lodash'
import { findOffset } from '../../services/offset_finder/offset_finder.service.js' 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 * EmojiInput - augmented inputs for emoji and autocomplete support in inputs
* without having to give up the comfort of <input/> and <textarea/> elements * without having to give up the comfort of <input/> and <textarea/> elements

View file

@ -11,7 +11,7 @@
class="emoji-picker-icon" class="emoji-picker-icon"
@click.prevent="togglePicker" @click.prevent="togglePicker"
> >
<i class="icon-smile" /> <FAIcon :icon="['far', 'smile-beam']" />
</div> </div>
<EmojiPicker <EmojiPicker
v-if="enableEmojiPicker" v-if="enableEmojiPicker"

View file

@ -1,4 +1,16 @@
import Checkbox from '../checkbox/checkbox.vue' 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, // At widest, approximately 20 emoji are visible in a row,
// loading 3 rows, could be overkill for narrow picker // loading 3 rows, could be overkill for narrow picker
@ -177,13 +189,13 @@ const EmojiPicker = {
{ {
id: 'custom', id: 'custom',
text: this.$t('emoji.custom'), text: this.$t('emoji.custom'),
icon: 'icon-smile', icon: 'smile-beam',
emojis: customEmojis emojis: customEmojis
}, },
{ {
id: 'standard', id: 'standard',
text: this.$t('emoji.unicode'), text: this.$t('emoji.unicode'),
icon: 'icon-picture', icon: 'underline',
emojis: filterByKeyword(standardEmojis, this.keyword) emojis: filterByKeyword(standardEmojis, this.keyword)
} }
] ]

View file

@ -82,7 +82,7 @@
&.active { &.active {
border-bottom: 4px solid; border-bottom: 4px solid;
i { svg {
color: $fallback--lightText; color: $fallback--lightText;
color: var(--lightText, $fallback--lightText); color: var(--lightText, $fallback--lightText);
} }

View file

@ -13,7 +13,7 @@
:title="group.text" :title="group.text"
@click.prevent="highlight(group.id)" @click.prevent="highlight(group.id)"
> >
<i :class="group.icon" /> <FAIcon :icon="group.icon" fixed-width/>
</span> </span>
</span> </span>
<span <span
@ -26,7 +26,7 @@
:title="$t('emoji.stickers')" :title="$t('emoji.stickers')"
@click.prevent="toggleStickers" @click.prevent="toggleStickers"
> >
<i class="icon-star" /> <FAIcon icon="sticky-note" fixed-width/>
</span> </span>
</span> </span>
</div> </div>

View file

@ -1,4 +1,8 @@
import Popover from '../popover/popover.vue' 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 = { const ExtraButtons = {
props: [ 'status' ], props: [ 'status' ],

View file

@ -73,9 +73,11 @@
</button> </button>
</div> </div>
</div> </div>
<i <FAIcon
slot="trigger" slot="trigger"
class="icon-ellipsis button-icon" class="button-icon"
icon="ellipsis-h"
size="lg"
/> />
</Popover> </Popover>
</template> </template>

View file

@ -1,4 +1,14 @@
import { mapGetters } from 'vuex' 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 = { const FavoriteButton = {
props: ['status', 'loggedIn'], props: ['status', 'loggedIn'],
@ -23,9 +33,7 @@ const FavoriteButton = {
computed: { computed: {
classes () { classes () {
return { return {
'icon-star-empty': !this.status.favorited, '-favorited': this.status.favorited
'icon-star': this.status.favorited,
'animate-spin': this.animated
} }
}, },
...mapGetters(['mergedConfig']) ...mapGetters(['mergedConfig'])

View file

@ -1,18 +1,23 @@
<template> <template>
<div v-if="loggedIn"> <div v-if="loggedIn">
<i <FAIcon
:class="classes" :class="classes"
class="button-icon favorite-button fav-active" class="FavoriteButton button-icon -interactive"
:title="$t('tool_tip.favorite')" :title="$t('tool_tip.favorite')"
:icon="[status.favorited ? 'fas' : 'far', 'star']"
:spin="animated"
size="lg"
@click.prevent="favorite()" @click.prevent="favorite()"
/> />
<span v-if="!mergedConfig.hidePostStats && status.fave_num > 0">{{ status.fave_num }}</span> <span v-if="!mergedConfig.hidePostStats && status.fave_num > 0">{{ status.fave_num }}</span>
</div> </div>
<div v-else> <div v-else>
<i <FAIcon
:class="classes" :class="classes"
class="button-icon favorite-button" class="FavoriteButton button-icon"
:title="$t('tool_tip.favorite')" :title="$t('tool_tip.favorite')"
:icon="['far', 'star']"
size="lg"
/> />
<span v-if="!mergedConfig.hidePostStats && status.fave_num > 0">{{ status.fave_num }}</span> <span v-if="!mergedConfig.hidePostStats && status.fave_num > 0">{{ status.fave_num }}</span>
</div> </div>
@ -23,7 +28,8 @@
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';
.fav-active { .FavoriteButton {
&.-interactive {
cursor: pointer; cursor: pointer;
animation-duration: 0.6s; animation-duration: 0.6s;
@ -33,8 +39,9 @@
} }
} }
.favorite-button.icon-star { &.-favorited {
color: $fallback--cOrange; color: $fallback--cOrange;
color: var(--cOrange, $fallback--cOrange); color: var(--cOrange, $fallback--cOrange);
} }
}
</style> </style>

View file

@ -2,6 +2,14 @@
import statusPosterService from '../../services/status_poster/status_poster.service.js' import statusPosterService from '../../services/status_poster/status_poster.service.js'
import fileSizeFormatService from '../../services/file_size_format/file_size_format.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 = { const mediaUpload = {
data () { data () {
return { return {

View file

@ -7,13 +7,15 @@
class="label" class="label"
:title="$t('tool_tip.media_upload')" :title="$t('tool_tip.media_upload')"
> >
<i <FAIcon
v-if="uploading" v-if="uploading"
class="progress-icon icon-spin4 animate-spin" class="progress-icon animate-spin"
icon="circle-notch"
/> />
<i <FAIcon
v-if="!uploading" v-if="!uploading"
class="new-icon icon-upload" class="new-icon"
icon="upload"
/> />
<input <input
v-if="uploadReady" v-if="uploadReady"

View file

@ -1,6 +1,29 @@
import { timelineNames } from '../timeline_menu/timeline_menu.js' import { timelineNames } from '../timeline_menu/timeline_menu.js'
import { mapState, mapGetters } from 'vuex' 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 = { const NavPanel = {
created () { created () {
if (this.currentUser && this.currentUser.locked) { if (this.currentUser && this.currentUser.locked) {

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="nav-panel"> <div class="NavPanel">
<div class="panel panel-default"> <div class="panel panel-default">
<ul> <ul>
<li v-if="currentUser || !privateMode"> <li v-if="currentUser || !privateMode">
@ -7,12 +7,14 @@
:to="{ name: timelinesRoute }" :to="{ name: timelinesRoute }"
:class="onTimelineRoute && 'router-link-active'" :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> </router-link>
</li> </li>
<li v-if="currentUser"> <li v-if="currentUser">
<router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }"> <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> </router-link>
</li> </li>
<li v-if="currentUser && pleromaChatMessagesAvailable"> <li v-if="currentUser && pleromaChatMessagesAvailable">
@ -23,12 +25,14 @@
> >
{{ unreadChatCount }} {{ unreadChatCount }}
</div> </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> </router-link>
</li> </li>
<li v-if="currentUser && currentUser.locked"> <li v-if="currentUser && currentUser.locked">
<router-link :to="{ name: 'friend-requests' }"> <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 <span
v-if="followRequestCount > 0" v-if="followRequestCount > 0"
class="badge follow-request-count" class="badge follow-request-count"
@ -39,7 +43,7 @@
</li> </li>
<li> <li>
<router-link :to="{ name: 'about' }"> <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> </router-link>
</li> </li>
</ul> </ul>
@ -52,11 +56,13 @@
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';
.nav-panel .panel { .NavPanel {
.panel {
overflow: hidden; overflow: hidden;
box-shadow: var(--panelShadow); box-shadow: var(--panelShadow);
} }
.nav-panel ul {
ul {
list-style: none; list-style: none;
margin: 0; margin: 0;
padding: 0; padding: 0;
@ -68,7 +74,7 @@
background-color: var(--input, $fallback--faint); background-color: var(--input, $fallback--faint);
} }
.nav-panel li { li {
border-bottom: 1px solid; border-bottom: 1px solid;
border-color: $fallback--border; border-color: $fallback--border;
border-color: var(--border, $fallback--border); border-color: var(--border, $fallback--border);
@ -89,11 +95,11 @@
} }
} }
.nav-panel li:last-child { li:last-child {
border: none; border: none;
} }
.nav-panel a { a {
display: block; display: block;
padding: 0.8em 0.85em; padding: 0.8em 0.85em;
@ -125,11 +131,13 @@
} }
} }
.nav-panel .button-icon { .button-icon {
margin-right: 0.5em; margin-left: -0.1em;
margin-right: 0.2em;
} }
.nav-panel .button-icon:before { .button-icon:before {
width: 1.1em; width: 1.1em;
} }
}
</style> </style>

View file

@ -1,5 +1,17 @@
import * as DateUtils from 'src/services/date_utils/date_utils.js' import * as DateUtils from 'src/services/date_utils/date_utils.js'
import { uniq } from 'lodash' 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 { export default {
name: 'PollForm', name: 'PollForm',

View file

@ -24,8 +24,8 @@
v-if="options.length > 2" v-if="options.length > 2"
class="icon-container" class="icon-container"
> >
<i <FAIcon
class="icon-cancel" icon="times"
@click="deleteOption(index)" @click="deleteOption(index)"
/> />
</div> </div>
@ -35,7 +35,8 @@
class="add-option faint" class="add-option faint"
@click="addOption" @click="addOption"
> >
<i class="icon-plus" /> <FAIcon icon="plus" size="sm"/>
{{ $t("polls.add_option") }} {{ $t("polls.add_option") }}
</a> </a>
<div class="poll-type-expiry"> <div class="poll-type-expiry">
@ -55,7 +56,7 @@
<option value="single">{{ $t('polls.single_choice') }}</option> <option value="single">{{ $t('polls.single_choice') }}</option>
<option value="multiple">{{ $t('polls.multiple_choices') }}</option> <option value="multiple">{{ $t('polls.multiple_choices') }}</option>
</select> </select>
<i class="icon-down-open" /> <FAIcon class="icon-down-open" icon="chevron-down"/>
</label> </label>
</div> </div>
<div <div
@ -83,7 +84,7 @@
{{ $t(`time.${unit}_short`, ['']) }} {{ $t(`time.${unit}_short`, ['']) }}
</option> </option>
</select> </select>
<i class="icon-down-open" /> <FAIcon class="icon-down-open" icon="chevron-down"/>
</label> </label>
</div> </div>
</div> </div>
@ -103,6 +104,7 @@
.add-option { .add-option {
align-self: flex-start; align-self: flex-start;
padding-top: 0.25em; padding-top: 0.25em;
padding-left: 0.1em;
cursor: pointer; cursor: pointer;
} }
@ -124,8 +126,8 @@
.icon-container { .icon-container {
// Hack: Move the icon over the input box // Hack: Move the icon over the input box
width: 2em; width: 1.5em;
margin-left: -2em; margin-left: -1.5em;
z-index: 1; z-index: 1;
} }

View file

@ -12,6 +12,23 @@ import suggestor from '../emoji_input/suggestor.js'
import { mapGetters, mapState } from 'vuex' import { mapGetters, mapState } from 'vuex'
import Checkbox from '../checkbox/checkbox.vue' 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) => { const buildMentionsString = ({ user, attentions = [] }, currentUser) => {
let allAttentions = [...attentions] let allAttentions = [...attentions]

View file

@ -12,10 +12,11 @@
v-show="showDropIcon !== 'hide'" v-show="showDropIcon !== 'hide'"
:style="{ animation: showDropIcon === 'show' ? 'fade-in 0.25s' : 'fade-out 0.5s' }" :style="{ animation: showDropIcon === 'show' ? 'fade-in 0.25s' : 'fade-out 0.5s' }"
class="drop-indicator" class="drop-indicator"
:class="[uploadFileLimitReached ? 'icon-block' : 'icon-upload']"
@dragleave="fileDragStop" @dragleave="fileDragStop"
@drop.stop="fileDrop" @drop.stop="fileDrop"
/> >
<FAIcon :icon="uploadFileLimitReached ? 'ban' : 'upload'"/>
</div>
<div class="form-group"> <div class="form-group">
<i18n <i18n
v-if="!$store.state.users.currentUser.locked && newStatus.visibility == 'private' && !disableLockWarning" v-if="!$store.state.users.currentUser.locked && newStatus.visibility == 'private' && !disableLockWarning"
@ -198,7 +199,7 @@
{{ $t(`post_status.content_type["${postFormat}"]`) }} {{ $t(`post_status.content_type["${postFormat}"]`) }}
</option> </option>
</select> </select>
<i class="icon-down-open" /> <FAIcon class="icon-down-open" icon="chevron-down"/>
</label> </label>
</div> </div>
<div <div
@ -235,22 +236,22 @@
<div <div
class="emoji-icon" class="emoji-icon"
> >
<i <div
:title="$t('emoji.add_emoji')" :title="$t('emoji.add_emoji')"
class="icon-smile btn btn-default" class="btn btn-default"
@click="showEmojiPicker" @click="showEmojiPicker"
/> >
<FAIcon icon="smile-beam"/>
</div>
</div> </div>
<div <div
v-if="pollsAvailable" v-if="pollsAvailable"
class="poll-icon" class="poll-icon"
:class="{ selected: pollFormVisible }" :class="{ selected: pollFormVisible }"
>
<i
:title="$t('polls.add_poll')" :title="$t('polls.add_poll')"
class="icon-chart-bar btn btn-default"
@click="togglePollForm" @click="togglePollForm"
/> >
<FAIcon icon="poll-h" />
</div> </div>
</div> </div>
<button <button
@ -392,7 +393,7 @@
&:hover { &:hover {
text-decoration: underline; text-decoration: underline;
} }
i { svg, i {
margin-left: 0.2em; margin-left: 0.2em;
font-size: 0.8em; font-size: 0.8em;
transform: rotate(90deg); transform: rotate(90deg);
@ -434,18 +435,20 @@
.media-upload-icon, .poll-icon, .emoji-icon { .media-upload-icon, .poll-icon, .emoji-icon {
font-size: 26px; font-size: 26px;
line-height: 1.1;
flex: 1; flex: 1;
padding: 0 0.1em;
&.selected, &:hover { &.selected, &:hover {
// needs to be specific to override icon default color // needs to be specific to override icon default color
i, label { svg, i, label {
color: $fallback--lightText; color: $fallback--lightText;
color: var(--lightText, $fallback--lightText); color: var(--lightText, $fallback--lightText);
} }
} }
&.disabled { &.disabled {
i { svg, i {
cursor: not-allowed; cursor: not-allowed;
color: $fallback--icon; color: $fallback--icon;
color: var(--btnDisabledText, $fallback--icon); color: var(--btnDisabledText, $fallback--icon);

View file

@ -1,4 +1,8 @@
import Popover from '../popover/popover.vue' 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 = { const ReactButton = {
props: ['status'], props: ['status'],

View file

@ -36,9 +36,11 @@
<div class="reaction-bottom-fader" /> <div class="reaction-bottom-fader" />
</div> </div>
</div> </div>
<i <FAIcon
slot="trigger" 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')" :title="$t('tool_tip.add_reaction')"
/> />
</Popover> </Popover>

View file

@ -1,3 +1,7 @@
import { library } from '@fortawesome/fontawesome-svg-core'
import { faReply } from '@fortawesome/free-solid-svg-icons'
library.add(faReply)
const ReplyButton = { const ReplyButton = {
name: 'ReplyButton', name: 'ReplyButton',

View file

@ -1,15 +1,19 @@
<template> <template>
<div> <div>
<i <FAIcon
v-if="loggedIn" v-if="loggedIn"
class="button-icon button-reply icon-reply" class="ReplyButton button-icon -interactive"
icon="reply"
size="lg"
:title="$t('tool_tip.reply')" :title="$t('tool_tip.reply')"
:class="{'-active': replying}" :class="{'-active': replying}"
@click.prevent="$emit('toggle')" @click.prevent="$emit('toggle')"
/> />
<i <FAIcon
v-else v-else
class="button-icon button-reply -disabled icon-reply" icon="reply"
size="lg"
class="ReplyButton button-icon"
:title="$t('tool_tip.reply')" :title="$t('tool_tip.reply')"
/> />
<span v-if="status.replies_count > 0"> <span v-if="status.replies_count > 0">
@ -19,3 +23,19 @@
</template> </template>
<script src="./reply_button.js"></script> <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>

View file

@ -1,3 +1,7 @@
import { library } from '@fortawesome/fontawesome-svg-core'
import { faRetweet } from '@fortawesome/free-solid-svg-icons'
library.add(faRetweet)
const RetweetButton = { const RetweetButton = {
props: ['status', 'loggedIn', 'visibility'], props: ['status', 'loggedIn', 'visibility'],
@ -22,9 +26,7 @@ const RetweetButton = {
computed: { computed: {
classes () { classes () {
return { return {
'retweeted': this.status.repeated, '-repeated': this.status.repeated
'retweeted-empty': !this.status.repeated,
'animate-spin': this.animated
} }
}, },
mergedConfig () { mergedConfig () {

View file

@ -1,26 +1,33 @@
<template> <template>
<div v-if="loggedIn"> <div v-if="loggedIn">
<template v-if="visibility !== 'private' && visibility !== 'direct'"> <template v-if="visibility !== 'private' && visibility !== 'direct'">
<i <FAIcon
:class="classes" :class="classes"
class="button-icon retweet-button icon-retweet rt-active" class="RetweetButton button-icon -interactive"
icon="retweet"
size="lg"
:spin="animated"
:title="$t('tool_tip.repeat')" :title="$t('tool_tip.repeat')"
@click.prevent="retweet()" @click.prevent="retweet()"
/> />
<span v-if="!mergedConfig.hidePostStats && status.repeat_num > 0">{{ status.repeat_num }}</span> <span v-if="!mergedConfig.hidePostStats && status.repeat_num > 0">{{ status.repeat_num }}</span>
</template> </template>
<template v-else> <template v-else>
<i <FAIcon
:class="classes" :class="classes"
class="button-icon icon-lock" class="RetweetButton button-icon"
icon="lock"
size="lg"
:title="$t('timeline.no_retweet_hint')" :title="$t('timeline.no_retweet_hint')"
/> />
</template> </template>
</div> </div>
<div v-else-if="!loggedIn"> <div v-else-if="!loggedIn">
<i <FAIcon
:class="classes" :class="classes"
class="button-icon icon-retweet" class="button-icon"
icon="retweet"
size="lg"
:title="$t('tool_tip.repeat')" :title="$t('tool_tip.repeat')"
/> />
<span v-if="!mergedConfig.hidePostStats && status.repeat_num > 0">{{ status.repeat_num }}</span> <span v-if="!mergedConfig.hidePostStats && status.repeat_num > 0">{{ status.repeat_num }}</span>
@ -31,16 +38,21 @@
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';
.rt-active {
.RetweetButton {
&.-interactive {
cursor: pointer; cursor: pointer;
animation-duration: 0.6s; animation-duration: 0.6s;
&:hover { &:hover {
color: $fallback--cGreen; color: $fallback--cGreen;
color: var(--cGreen, $fallback--cGreen); color: var(--cGreen, $fallback--cGreen);
} }
} }
.icon-retweet.retweeted {
&.-repeated {
color: $fallback--cGreen; color: $fallback--cGreen;
color: var(--cGreen, $fallback--cGreen); color: var(--cGreen, $fallback--cGreen);
} }
}
</style> </style>

View file

@ -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 = { const ScopeSelector = {
props: [ props: [
'showAll', 'showAll',

View file

@ -1,36 +1,44 @@
<template> <template>
<div <div
v-if="!showNothing" v-if="!showNothing"
class="scope-selector" class="ScopeSelector"
> >
<i <span
v-if="showDirect" v-if="showDirect"
class="icon-mail-alt" class="scope"
:class="css.direct" :class="css.direct"
:title="$t('post_status.scope.direct')" :title="$t('post_status.scope.direct')"
@click="changeVis('direct')" @click="changeVis('direct')"
/> >
<i <FAIcon icon="envelope" class="button-icon" size="lg" />
</span>
<span
class="scope"
v-if="showPrivate" v-if="showPrivate"
class="icon-lock"
:class="css.private" :class="css.private"
:title="$t('post_status.scope.private')" :title="$t('post_status.scope.private')"
@click="changeVis('private')" @click="changeVis('private')"
/> >
<i <FAIcon icon="lock" class="button-icon" size="lg" />
</span>
<span
v-if="showUnlisted" v-if="showUnlisted"
class="icon-lock-open-alt" class="scope"
:class="css.unlisted" :class="css.unlisted"
:title="$t('post_status.scope.unlisted')" :title="$t('post_status.scope.unlisted')"
@click="changeVis('unlisted')" @click="changeVis('unlisted')"
/> >
<i <FAIcon icon="lock-open" class="button-icon" size="lg" />
</span>
<span
v-if="showPublic" v-if="showPublic"
class="icon-globe" class="scope"
:class="css.public" :class="css.public"
:title="$t('post_status.scope.public')" :title="$t('post_status.scope.public')"
@click="changeVis('public')" @click="changeVis('public')"
/> >
<FAIcon icon="globe-europe" class="button-icon" size="lg" />
</span>
</div> </div>
</template> </template>
@ -39,12 +47,16 @@
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';
.scope-selector { .ScopeSelector {
i {
font-size: 1.2em;
cursor: pointer;
&.selected { .scope {
display: inline-block;
cursor: pointer;
min-width: 1.3em;
min-height: 1.3em;
text-align: center;
&.selected svg {
color: $fallback--lightText; color: $fallback--lightText;
color: var(--lightText, $fallback--lightText); color: var(--lightText, $fallback--lightText);
} }

View file

@ -17,6 +17,47 @@ import { highlightClass, highlightStyle } from '../../services/user_highlighter/
import { muteWordHits } from '../../services/status_parser/status_parser.js' import { muteWordHits } from '../../services/status_parser/status_parser.js'
import { unescape, uniqBy } from 'lodash' 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 = { const Status = {
name: 'Status', name: 'Status',
components: { components: {
@ -227,13 +268,13 @@ const Status = {
visibilityIcon (visibility) { visibilityIcon (visibility) {
switch (visibility) { switch (visibility) {
case 'private': case 'private':
return 'icon-lock' return 'lock'
case 'unlisted': case 'unlisted':
return 'icon-lock-open-alt' return 'lock-open'
case 'direct': case 'direct':
return 'icon-mail-alt' return 'envelope'
default: default:
return 'icon-globe' return 'globe-europe'
} }
}, },
showError (error) { showError (error) {

View file

@ -200,7 +200,6 @@ $status-margin: 0.75em;
} }
.reply-to { .reply-to {
display: flex;
position: relative; position: relative;
} }
@ -208,7 +207,6 @@ $status-margin: 0.75em;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
margin-left: 0.2em;
} }
.replies-separator { .replies-separator {
@ -232,16 +230,10 @@ $status-margin: 0.75em;
.repeat-info { .repeat-info {
padding: 0.4em $status-margin; padding: 0.4em $status-margin;
line-height: 22px;
.right-side { .repeat-icon {
display: flex; color: $fallback--cGreen;
align-content: center; color: var(--cGreen, $fallback--cGreen);
flex-wrap: wrap;
}
i {
padding: 0 0.2em;
} }
} }
@ -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 { .muted {
padding: 0.25em 0.6em; padding: 0.25em 0.6em;
height: 1.2em; height: 1.2em;

View file

@ -10,17 +10,20 @@
class="alert error" class="alert error"
> >
{{ error }} {{ error }}
<i <span
class="button-icon icon-cancel" class="button-icon"
@click="clearError" @click="clearError"
/> >
<FAIcon icon="times" />
</span>
</div> </div>
<template v-if="muted && !isPreview"> <template v-if="muted && !isPreview">
<div class="status-container muted"> <div class="status-container muted">
<small class="status-username"> <small class="status-username">
<i <FAIcon
v-if="muted && retweet" v-if="muted && retweet"
class="button-icon icon-retweet" class="button-icon repeat-icon"
icon="retweet"
/> />
<router-link :to="userProfileLink"> <router-link :to="userProfileLink">
{{ status.user.screen_name }} {{ status.user.screen_name }}
@ -46,9 +49,11 @@
</small> </small>
<a <a
href="#" href="#"
class="unmute" class="unmute button-icon"
@click.prevent="toggleMute" @click.prevent="toggleMute"
><i class="button-icon icon-eye-off" /></a> >
<FAIcon icon="eye-slash" class="button-icon" size="lg" />
</a>
</div> </div>
</template> </template>
<template v-else> <template v-else>
@ -56,7 +61,7 @@
v-if="showPinned" v-if="showPinned"
class="pin" class="pin"
> >
<i class="fa icon-pin faint" /> <FAIcon icon="thumbtack" class="faint" />
<span class="faint">{{ $t('status.pinned') }}</span> <span class="faint">{{ $t('status.pinned') }}</span>
</div> </div>
<div <div
@ -86,8 +91,9 @@
:to="retweeterProfileLink" :to="retweeterProfileLink"
>{{ retweeter }}</router-link> >{{ retweeter }}</router-link>
</span> </span>
<i <FAIcon
class="fa icon-retweet retweeted" icon="retweet"
class="repeat-icon"
:title="$t('tool_tip.repeat')" :title="$t('tool_tip.repeat')"
/> />
{{ $t('timeline.repeated') }} {{ $t('timeline.repeated') }}
@ -167,15 +173,13 @@
:auto-update="60" :auto-update="60"
/> />
</router-link> </router-link>
<div <span
v-if="status.visibility" v-if="status.visibility"
class="button-icon visibility-icon" class="visibility-icon"
>
<i
:class="visibilityIcon(status.visibility)"
:title="status.visibility | capitalize" :title="status.visibility | capitalize"
/> >
</div> <FAIcon class="button-icon" :icon="visibilityIcon(status.visibility)" size="lg" />
</span>
<a <a
v-if="!status.is_local && !isPreview" v-if="!status.is_local && !isPreview"
:href="status.external_url" :href="status.external_url"
@ -183,22 +187,23 @@
class="source_url" class="source_url"
title="Source" title="Source"
> >
<i class="button-icon icon-link-ext-alt" /> <FAIcon class="button-icon" icon="external-link-square-alt" size="lg" />
</a> </a>
<template v-if="expandable && !isPreview">
<a <a
v-if="expandable && !isPreview"
href="#" href="#"
title="Expand" title="Expand"
@click.prevent="toggleExpanded" @click.prevent="toggleExpanded"
> >
<i class="button-icon icon-plus-squared" /> <FAIcon class="button-icon" icon="plus-square" size="lg" />
</a> </a>
</template>
<a <a
v-if="unmuted" v-if="unmuted"
href="#" href="#"
@click.prevent="toggleMute" @click.prevent="toggleMute"
><i class="button-icon icon-eye-off" /></a> >
<FAIcon icon="eye-slash" class="button-icon" size="lg" />
</a>
</span> </span>
</div> </div>
@ -220,7 +225,12 @@
:aria-label="$t('tool_tip.reply')" :aria-label="$t('tool_tip.reply')"
@click.prevent="gotoOriginal(status.in_reply_to_status_id)" @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 <span
class="faint-link reply-to-text" class="faint-link reply-to-text"
> >

View file

@ -1,5 +1,23 @@
import Popover from '../popover/popover.vue' import Popover from '../popover/popover.vue'
import { mapState } from 'vuex' 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 // Route -> i18n key mapping, exported andnot in the computed
// because nav panel benefits from the same information. // because nav panel benefits from the same information.

View file

@ -1,7 +1,7 @@
<template> <template>
<Popover <Popover
trigger="click" trigger="click"
class="timeline-menu" class="TimelineMenu"
:class="{ 'open': isOpen }" :class="{ 'open': isOpen }"
:margin="{ left: -15, right: -200 }" :margin="{ left: -15, right: -200 }"
:bound-to="{ x: 'container' }" :bound-to="{ x: 'container' }"
@ -16,27 +16,27 @@
<ul> <ul>
<li v-if="currentUser"> <li v-if="currentUser">
<router-link :to="{ name: 'friends' }"> <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> </router-link>
</li> </li>
<li v-if="currentUser"> <li v-if="currentUser">
<router-link :to="{ name: 'bookmarks'}"> <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> </router-link>
</li> </li>
<li v-if="currentUser"> <li v-if="currentUser">
<router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }"> <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> </router-link>
</li> </li>
<li v-if="currentUser || !privateMode"> <li v-if="currentUser || !privateMode">
<router-link :to="{ name: 'public-timeline' }"> <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> </router-link>
</li> </li>
<li v-if="federating && (currentUser || !privateMode)"> <li v-if="federating && (currentUser || !privateMode)">
<router-link :to="{ name: 'public-external-timeline' }"> <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> </router-link>
</li> </li>
</ul> </ul>
@ -46,7 +46,7 @@
class="title timeline-menu-title" class="title timeline-menu-title"
> >
<span>{{ timelineName() }}</span> <span>{{ timelineName() }}</span>
<i class="icon-down-open" /> <FAIcon size="sm" icon="chevron-down" />
</div> </div>
</Popover> </Popover>
</template> </template>
@ -56,17 +56,19 @@
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';
.timeline-menu { .TimelineMenu {
flex-shrink: 1; flex-shrink: 1;
margin-right: auto; margin-right: auto;
min-width: 0; min-width: 0;
width: 24rem; width: 24rem;
.timeline-menu-popover-wrap { .timeline-menu-popover-wrap {
overflow: hidden; overflow: hidden;
// Match panel heading padding to line up menu with bottom of heading // Match panel heading padding to line up menu with bottom of heading
margin-top: 0.6rem; margin-top: 0.6rem;
padding: 0 15px 15px 15px; padding: 0 15px 15px 15px;
} }
.timeline-menu-popover { .timeline-menu-popover {
width: 24rem; width: 24rem;
max-width: 100vw; max-width: 100vw;
@ -77,10 +79,12 @@
transform: translateY(-100%); transform: translateY(-100%);
transition: transform 100ms; transition: transform 100ms;
} }
.panel::after { .panel::after {
border-top-right-radius: 0; border-top-right-radius: 0;
border-top-left-radius: 0; border-top-left-radius: 0;
} }
&.open .timeline-menu-popover { &.open .timeline-menu-popover {
transform: translateY(0); transform: translateY(0);
} }
@ -88,7 +92,6 @@
.timeline-menu-title { .timeline-menu-title {
margin: 0; margin: 0;
cursor: pointer; cursor: pointer;
display: flex;
user-select: none; user-select: none;
width: 100%; width: 100%;
@ -98,15 +101,13 @@
white-space: nowrap; white-space: nowrap;
} }
i { svg {
margin-left: 0.6em; margin-left: 0.6em;
flex-shrink: 0;
font-size: 1rem;
transition: transform 100ms; transition: transform 100ms;
} }
} }
&.open .timeline-menu-title i { &.open .timeline-menu-title svg {
color: $fallback--text; color: $fallback--text;
color: var(--panelText, $fallback--text); color: var(--panelText, $fallback--text);
transform: rotate(180deg); transform: rotate(180deg);
@ -171,8 +172,9 @@
} }
} }
i { svg {
margin-right: 0.5em; margin-right: 0.4em;
margin-left: -0.2em;
} }
} }
} }

View file

@ -33,6 +33,8 @@ import VueClickOutside from 'v-click-outside'
import PortalVue from 'portal-vue' import PortalVue from 'portal-vue'
import VBodyScrollLock from './directives/body_scroll_lock' import VBodyScrollLock from './directives/body_scroll_lock'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import afterStoreSetup from './boot/after_store.js' import afterStoreSetup from './boot/after_store.js'
const currentLocale = (window.navigator.language || 'en').split('-')[0] const currentLocale = (window.navigator.language || 'en').split('-')[0]
@ -45,6 +47,8 @@ Vue.use(VueClickOutside)
Vue.use(PortalVue) Vue.use(PortalVue)
Vue.use(VBodyScrollLock) Vue.use(VBodyScrollLock)
Vue.component('FAIcon', FontAwesomeIcon)
const i18n = new VueI18n({ const i18n = new VueI18n({
// By default, use the browser locale, we will update it if neccessary // By default, use the browser locale, we will update it if neccessary
locale: 'en', locale: 'en',

View file

@ -884,6 +884,37 @@
dependencies: dependencies:
qrcode "^1.3.0" 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": "@nodelib/fs.scandir@2.1.3":
version "2.1.3" version "2.1.3"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b"