diff options
Diffstat (limited to 'src/components/mention_link')
| -rw-r--r-- | src/components/mention_link/mention_link.js | 63 | ||||
| -rw-r--r-- | src/components/mention_link/mention_link.scss | 55 | ||||
| -rw-r--r-- | src/components/mention_link/mention_link.vue | 93 |
3 files changed, 157 insertions, 54 deletions
diff --git a/src/components/mention_link/mention_link.js b/src/components/mention_link/mention_link.js index 65c62baa..6515bd11 100644 --- a/src/components/mention_link/mention_link.js +++ b/src/components/mention_link/mention_link.js @@ -1,6 +1,9 @@ import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import { mapGetters, mapState } from 'vuex' import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js' +import UserAvatar from '../user_avatar/user_avatar.vue' +import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue' +import { defineAsyncComponent } from 'vue' import { library } from '@fortawesome/fontawesome-svg-core' import { faAt @@ -12,6 +15,11 @@ library.add( const MentionLink = { name: 'MentionLink', + components: { + UserAvatar, + UnicodeDomainIndicator, + UserPopover: defineAsyncComponent(() => import('../user_popover/user_popover.vue')) + }, props: { url: { required: true, @@ -30,15 +38,30 @@ const MentionLink = { type: String } }, + data () { + return { + hasSelection: false + } + }, methods: { onClick () { + if (this.shouldShowTooltip) return const link = generateProfileLink( this.userId || this.user.id, this.userScreenName || this.user.screen_name ) this.$router.push(link) + }, + handleSelection () { + this.hasSelection = document.getSelection().containsNode(this.$refs.full, true) } }, + mounted () { + document.addEventListener('selectionchange', this.handleSelection) + }, + unmounted () { + document.removeEventListener('selectionchange', this.handleSelection) + }, computed: { user () { return this.url && this.$store && this.$store.getters.findUserByUrl(this.url) @@ -50,6 +73,10 @@ const MentionLink = { userName () { return this.user && this.userNameFullUi.split('@')[0] }, + serverName () { + // XXX assumed that domain does not contain @ + return this.user && (this.userNameFullUi.split('@')[1] || this.$store.getters.instanceDomain) + }, userNameFull () { return this.user && this.user.screen_name }, @@ -79,12 +106,44 @@ const MentionLink = { classnames () { return [ { - '-you': this.isYou, - '-highlighted': this.highlight + '-you': this.isYou && this.shouldBoldenYou, + '-highlighted': this.highlight, + '-has-selection': this.hasSelection }, this.highlightType ] }, + useAtIcon () { + return this.mergedConfig.useAtIcon + }, + isRemote () { + return this.userName !== this.userNameFull + }, + shouldShowFullUserName () { + const conf = this.mergedConfig.mentionLinkDisplay + if (conf === 'short') { + return false + } else if (conf === 'full') { + return true + } else { // full_for_remote + return this.isRemote + } + }, + shouldShowTooltip () { + return this.mergedConfig.mentionLinkShowTooltip + }, + shouldShowAvatar () { + return this.mergedConfig.mentionLinkShowAvatar + }, + shouldShowYous () { + return this.mergedConfig.mentionLinkShowYous + }, + shouldBoldenYou () { + return this.mergedConfig.mentionLinkBoldenYou + }, + shouldFadeDomain () { + return this.mergedConfig.mentionLinkFadeDomain + }, ...mapGetters(['mergedConfig']), ...mapState({ currentUser: state => state.users.currentUser diff --git a/src/components/mention_link/mention_link.scss b/src/components/mention_link/mention_link.scss index ec2689f8..8b2af926 100644 --- a/src/components/mention_link/mention_link.scss +++ b/src/components/mention_link/mention_link.scss @@ -1,15 +1,27 @@ +@import '../../_variables.scss'; + .MentionLink { position: relative; white-space: normal; - display: inline-block; + display: inline; color: var(--link); + word-break: normal; & .new, & .original { - display: inline-block; + display: inline; border-radius: 2px; } + .mention-avatar { + border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); + width: 1.5em; + height: 1.5em; + vertical-align: middle; + user-select: none; + margin-right: 0.2em; + } + .full { position: absolute; display: inline-block; @@ -27,7 +39,8 @@ user-select: all; } - .short { + & .short.-with-tooltip, + & .you { user-select: none; } @@ -36,19 +49,25 @@ white-space: nowrap; } + .shortName { + white-space: normal; + } + .new { &.-you { - & .shortName, - & .full { + .shortName { font-weight: 600; } } + &.-has-selection { + color: var(--alertNeutralText, $fallback--text); + background-color: var(--alertNeutral, $fallback--fg); + } .at { color: var(--link); opacity: 0.8; display: inline-block; - height: 50%; line-height: 1; padding: 0 0.1em; vertical-align: -25%; @@ -56,8 +75,7 @@ } &.-striped { - & .userName, - & .full { + & .shortName { background-image: repeating-linear-gradient( 135deg, @@ -70,22 +88,29 @@ } &.-solid { - & .userName, - & .full { + .shortName { background-image: linear-gradient(var(--____highlight-tintColor2), var(--____highlight-tintColor2)); } } &.-side { - & .userName, - & .userNameFull { + .shortName { box-shadow: 0 -5px 3px -4px inset var(--____highlight-solidColor); } } } - &:hover .new .full { - opacity: 1; - pointer-events: initial; + .full { + pointer-events: none; } + + .serverName.-faded { + color: var(--faintLink, $fallback--link); + } +} + +.mention-link-popover { + max-width: 70ch; + max-height: 20rem; + overflow: hidden; } diff --git a/src/components/mention_link/mention_link.vue b/src/components/mention_link/mention_link.vue index a22b486c..869a3257 100644 --- a/src/components/mention_link/mention_link.vue +++ b/src/components/mention_link/mention_link.vue @@ -9,48 +9,67 @@ class="original" target="_blank" v-html="content" - /> - <!-- eslint-enable vue/no-v-html --> - <span - v-if="user" - class="new" - :style="style" - :class="classnames" + /><!-- eslint-enable vue/no-v-html --> + <UserPopover + v-else + :user-id="user.id" + :disabled="!shouldShowTooltip" > - <a - class="short button-unstyled" - :href="url" - @click.prevent="onClick" - > - <!-- eslint-disable vue/no-v-html --> - <FAIcon - size="sm" - icon="at" - class="at" - /><span class="shortName"><span - class="userName" - v-html="userName" - /></span> - <span - v-if="isYou" - class="you" - >{{ $t('status.you') }}</span> - <!-- eslint-enable vue/no-v-html --> - </a> <span - v-if="userName !== userNameFull" - class="full popover-default" - :class="[highlightType]" + v-if="user" + class="new" + :style="style" + :class="classnames" > - <span - class="userNameFull" - v-text="'@' + userNameFull" - /> + <a + class="short button-unstyled" + :class="{ '-with-tooltip': shouldShowTooltip }" + :href="url" + @click.prevent="onClick" + > + <!-- eslint-disable vue/no-v-html --> + <UserAvatar + v-if="shouldShowAvatar" + class="mention-avatar" + :user="user" + /><span + class="shortName" + ><FAIcon + v-if="useAtIcon" + size="sm" + icon="at" + class="at" + />{{ !useAtIcon ? '@' : '' }}<span + class="userName" + v-html="userName" + /><span + v-if="shouldShowFullUserName" + class="serverName" + :class="{ '-faded': shouldFadeDomain }" + v-html="'@' + serverName" + /><UnicodeDomainIndicator + v-if="shouldShowFullUserName" + :user="user" + /> + </span> + <span + v-if="isYou && shouldShowYous" + :class="{ '-you': shouldBoldenYou }" + > {{ ' ' + $t('status.you') }}</span> + <!-- eslint-enable vue/no-v-html --> + </a><span + ref="full" + class="full" + > + <!-- eslint-disable vue/no-v-html --> + @<span v-html="userName" /><span v-html="'@' + serverName" /> + <!-- eslint-enable vue/no-v-html --> + </span> </span> - </span> + </UserPopover> </span> </template> -<script src="./mention_link.js"/> +<script src="./mention_link.js" /> -<style lang="scss" src="./mention_link.scss"/> +<style lang="scss" src="./mention_link.scss" /> |
