diff --git a/src/components/mention_link/mention_link.js b/src/components/mention_link/mention_link.js index 65c62baa0c..5209907da4 100644 --- a/src/components/mention_link/mention_link.js +++ b/src/components/mention_link/mention_link.js @@ -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 diff --git a/src/components/mention_link/mention_link.scss b/src/components/mention_link/mention_link.scss index ec2689f8d7..03306dcc73 100644 --- a/src/components/mention_link/mention_link.scss +++ b/src/components/mention_link/mention_link.scss @@ -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); + } } diff --git a/src/components/mention_link/mention_link.vue b/src/components/mention_link/mention_link.vue index a22b486c34..ac20eb5af0 100644 --- a/src/components/mention_link/mention_link.vue +++ b/src/components/mention_link/mention_link.vue @@ -19,17 +19,30 @@ > - {{ !useAtIcon ? '@' : '' }} + > + + @ + + diff --git a/src/components/settings_modal/tabs/general_tab.js b/src/components/settings_modal/tabs/general_tab.js index eeda61bf7c..952c328dee 100644 --- a/src/components/settings_modal/tabs/general_tab.js +++ b/src/components/settings_modal/tabs/general_tab.js @@ -20,6 +20,11 @@ const GeneralTab = { value: mode, label: this.$t(`settings.subject_line_${mode === 'masto' ? 'mastodon' : 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') || diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index bd3ee84ee6..44b1ac9265 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -147,6 +147,41 @@ {{ $t('settings.greentext') }} +
  • + + {{ $t('settings.mention_link_display') }} + +
  • + diff --git a/src/i18n/en.json b/src/i18n/en.json index 4be744a3fc..209fd18419 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -485,6 +485,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", diff --git a/src/modules/config.js b/src/modules/config.js index c79302b551..9f2d4ef384 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -11,7 +11,8 @@ const browserLocale = (window.navigator.language || 'en').split('-')[0] */ export const multiChoiceProperties = [ 'postContentType', - 'subjectLineBehavior' + 'subjectLineBehavior', + 'mentionLinkDisplay' // short | full_for_remote | full ] export const defaultState = { @@ -70,6 +71,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 diff --git a/src/modules/instance.js b/src/modules/instance.js index 60038f08b9..d686f25835 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -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, // bad name: actually hides posts of muted USERS hideMutedPosts: 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: {