Enhanced mention link

https://git.pleroma.social/pleroma/pleroma-fe/-/merge_requests/1424

Signed-off-by: Sam Therapy <sam@samtherapy.net>
This commit is contained in:
Sam Therapy 2022-01-22 11:34:00 -06:00
parent 3f113d3a69
commit 8e71f0a093
Signed by: sam
GPG key ID: 4D8B07C18F31ACBD
8 changed files with 147 additions and 9 deletions

View file

@ -1,6 +1,7 @@
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 { library } from '@fortawesome/fontawesome-svg-core'
import {
faAt
@ -12,6 +13,9 @@ library.add(
const MentionLink = {
name: 'MentionLink',
components: {
UserAvatar
},
props: {
url: {
required: true,
@ -50,6 +54,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
},
@ -85,6 +93,31 @@ const MentionLink = {
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 && this.mergedConfig.mentionLinkDisplay === 'short' && this.isRemote
},
shouldShowAvatar () {
return this.mergedConfig.mentionLinkShowAvatar
},
shouldFadeDomain () {
return this.mergedConfig.mentionLinkFadeDomain
},
...mapGetters(['mergedConfig']),
...mapState({
currentUser: state => state.users.currentUser

View file

@ -1,3 +1,5 @@
@import '../../_variables.scss';
.MentionLink {
position: relative;
white-space: normal;
@ -10,6 +12,15 @@
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 +38,8 @@
user-select: all;
}
.short {
.short.-with-tooltip,
.you {
user-select: none;
}
@ -56,7 +68,7 @@
}
&.-striped {
& .userName,
& .shortName,
& .full {
background-image:
repeating-linear-gradient(
@ -70,14 +82,14 @@
}
&.-solid {
& .userName,
& .shortName,
& .full {
background-image: linear-gradient(var(--____highlight-tintColor2), var(--____highlight-tintColor2));
}
}
&.-side {
& .userName,
& .shortName,
& .userNameFull {
box-shadow: 0 -5px 3px -4px inset var(--____highlight-solidColor);
}
@ -88,4 +100,12 @@
opacity: 1;
pointer-events: initial;
}
.serverName.-faded {
color: var(--faintLink, $fallback--link);
}
.full .-faded {
color: var(--faint, $fallback--faint);
}
}

View file

@ -19,17 +19,30 @@
>
<a
class="short button-unstyled"
:class="{ '-with-tooltip': shouldShowTooltip }"
:href="url"
@click.prevent="onClick"
>
<!-- eslint-disable vue/no-v-html -->
<FAIcon
<UserAvatar
v-if="shouldShowAvatar"
class="mention-avatar"
:user="user"
/><span
class="shortName"
><FAIcon
v-if="useAtIcon"
size="sm"
icon="at"
class="at"
/><span class="shortName"><span
/>{{ !useAtIcon ? '@' : '' }}<span
class="userName"
v-html="userName"
/><span
v-if="shouldShowFullUserName"
class="serverName"
:class="{ '-faded': shouldFadeDomain }"
v-html="'@' + serverName"
/></span>
<span
v-if="isYou"
@ -38,14 +51,24 @@
<!-- eslint-enable vue/no-v-html -->
</a>
<span
v-if="userName !== userNameFull"
v-if="shouldShowTooltip"
class="full popover-default"
:class="[highlightType]"
>
<span
class="userNameFull"
v-text="'@' + userNameFull"
/>
>
<!-- eslint-disable vue/no-v-html -->
@<span
class="userName"
v-html="userName"
/><span
class="serverName"
:class="{ '-faded': shouldFadeDomain }"
v-html="'@' + serverName"
/>
<!-- eslint-enable vue/no-v-html -->
</span>
</span>
</span>
</span>

View file

@ -30,6 +30,11 @@ const GeneralTab = {
value: mode,
label: this.$t(`settings.conversation_other_replies_button_${mode}`)
})),
mentionLinkDisplayOptions: [ 'short', 'full_for_remote', 'full' ].map(mode => ({
key: mode,
value: mode,
label: this.$t(`settings.mention_link_display_${mode}`)
})),
loopSilentAvailable:
// Firefox
Object.getOwnPropertyDescriptor(HTMLVideoElement.prototype, 'mozHasAudio') ||

View file

@ -134,6 +134,41 @@
</ChoiceSetting>
</li>
</ul>
<li>
<ChoiceSetting
id="mentionLinkDisplay"
path="mentionLinkDisplay"
:options="mentionLinkDisplayOptions"
>
{{ $t('settings.mention_link_display') }}
</ChoiceSetting>
</li>
<ul
class="setting-list suboptions"
>
<li
v-if="mentionLinkDisplay === 'short'"
>
<BooleanSetting path="mentionLinkShowTooltip">
{{ $t('settings.mention_link_show_tooltip') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="useAtIcon">
{{ $t('settings.use_at_icon') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="mentionLinkShowAvatar">
{{ $t('settings.mention_link_show_avatar') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="mentionLinkFadeDomain">
{{ $t('settings.mention_link_fade_domain') }}
</BooleanSetting>
</li>
</ul>
</ul>
</div>

View file

@ -491,6 +491,14 @@
"true": "yes"
},
"virtual_scrolling": "Optimize timeline rendering",
"use_at_icon": "Display @ symbol as an icon instead of text",
"mention_link_display": "Display mention links",
"mention_link_display_short": "always as short names (e.g. @foo)",
"mention_link_display_full_for_remote": "as full names only for remote users (e.g. @foo@example.org)",
"mention_link_display_full": "always as full names (e.g. @foo@example.org)",
"mention_link_show_tooltip": "Show full user names as tooltip for remote users",
"mention_link_show_avatar": "Show user avatar beside the link",
"mention_link_fade_domain": "Fade domains (e.g. @example.org in @foo@example.org)",
"fun": "Fun",
"greentext": "Meme arrows",
"notifications": "Notifications",

View file

@ -12,6 +12,7 @@ const browserLocale = (window.navigator.language || 'en').split('-')[0]
export const multiChoiceProperties = [
'postContentType',
'subjectLineBehavior',
'mentionLinkDisplay', // short | full_for_remote | full
'conversationDisplay', // tree | linear
'conversationOtherRepliesButton' // below | inside
]
@ -75,6 +76,11 @@ export const defaultState = {
useOneClickNsfw: false,
useContainFit: false,
greentext: undefined, // instance default
useAtIcon: undefined, // instance default
mentionLinkDisplay: undefined, // instance default
mentionLinkShowTooltip: undefined, // instance default
mentionLinkShowAvatar: undefined, // instance default
mentionLinkFadeDomain: undefined, // instance default
hidePostStats: undefined, // instance default
hideUserStats: undefined, // instance default
virtualScrolling: undefined, // instance default

View file

@ -20,6 +20,11 @@ const defaultState = {
background: '/static/aurora_borealis.jpg',
collapseMessageWithSubject: false,
greentext: false,
useAtIcon: false,
mentionLinkDisplay: 'short',
mentionLinkShowTooltip: true,
mentionLinkShowAvatar: false,
mentionLinkFadeDomain: true,
hideFilteredStatuses: false,
hideMutedPosts: false,
hidePostStats: false,
@ -100,6 +105,9 @@ const instance = {
return instanceDefaultProperties
.map(key => [key, state[key]])
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {})
},
instanceDomain (state) {
return new URL(state.server).hostname
}
},
actions: {