From ed8bc6102290cb50d44c1c7aa5696aac5624d907 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Wed, 22 Jun 2022 16:05:27 -0400
Subject: Add last edited at indicator in status

---
 src/components/status/status.vue | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

(limited to 'src/components/status/status.vue')

diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 67ce999a..a9630a53 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -328,6 +328,30 @@
                 class="mentions-line"
               />
             </div>
+            <div
+              v-if="isEdited && editingAvailable"
+              class="heading-edited-row"
+            >
+              <i18n-t
+                keypath="status.edited_at"
+                tag="span"
+              >
+                <template #time>
+                  <i18n-t
+                    keypath="time.in_past"
+                    tag="span"
+                  >
+                    <template>
+                      <Timeago
+                        :time="status.edited_at"
+                        :auto-update="60"
+                        :long-format="true"
+                      />
+                    </template>
+                  </i18n-t>
+                </template>
+              </i18n-t>
+            </div>
           </div>
 
           <StatusContent
-- 
cgit v1.2.3-70-g09d2


From acd53957e09a499b04c8f901e5829607f7363b57 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Wed, 22 Jun 2022 16:14:19 -0400
Subject: Do not show edited indicator in history items

---
 src/components/status/status.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/components/status/status.vue')

diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index a9630a53..00462f0a 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -329,7 +329,7 @@
               />
             </div>
             <div
-              v-if="isEdited && editingAvailable"
+              v-if="isEdited && editingAvailable && !isPreview"
               class="heading-edited-row"
             >
               <i18n-t
-- 
cgit v1.2.3-70-g09d2


From 232cc72df8352db15ac3e6b11c1f9c5908069771 Mon Sep 17 00:00:00 2001
From: Sean King <seanking2919@protonmail.com>
Date: Mon, 1 Aug 2022 18:45:52 -0600
Subject: Fix lint errors and warnings

---
 src/components/edit_status_modal/edit_status_modal.vue       |  6 +++---
 src/components/status/status.vue                             | 12 +++++-------
 src/components/status_history_modal/status_history_modal.vue |  4 ++--
 src/services/api/api.service.js                              |  6 +++---
 src/services/entity_normalizer/entity_normalizer.service.js  |  2 +-
 5 files changed, 14 insertions(+), 16 deletions(-)

(limited to 'src/components/status/status.vue')

diff --git a/src/components/edit_status_modal/edit_status_modal.vue b/src/components/edit_status_modal/edit_status_modal.vue
index 00dde7de..1dbacaab 100644
--- a/src/components/edit_status_modal/edit_status_modal.vue
+++ b/src/components/edit_status_modal/edit_status_modal.vue
@@ -11,10 +11,10 @@
       <PostStatusForm
         class="panel-body"
         v-bind="params"
-        @posted="closeModal"
-        :disablePolls="true"
-        :disableVisibilitySelector="true"
         :post-handler="doEditStatus"
+        :disable-polls="true"
+        :disable-visibility-selector="true"
+        @posted="closeModal"
       />
     </div>
   </Modal>
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index a13e5ab0..5ddb94b4 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -340,13 +340,11 @@
                     keypath="time.in_past"
                     tag="span"
                   >
-                    <template>
-                      <Timeago
-                        :time="status.edited_at"
-                        :auto-update="60"
-                        :long-format="true"
-                      />
-                    </template>
+                    <Timeago
+                      :time="status.edited_at"
+                      :auto-update="60"
+                      :long-format="true"
+                    />
                   </i18n-t>
                 </template>
               </i18n-t>
diff --git a/src/components/status_history_modal/status_history_modal.vue b/src/components/status_history_modal/status_history_modal.vue
index d6680df2..990be35b 100644
--- a/src/components/status_history_modal/status_history_modal.vue
+++ b/src/components/status_history_modal/status_history_modal.vue
@@ -17,9 +17,9 @@
             v-for="status in history"
             :key="status.id"
             :statusoid="status"
-            :isPreview="true"
+            :is-preview="true"
             class="conversation-status status-fadein panel-body"
-        />
+          />
         </div>
       </div>
     </div>
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index 41c14596..381dd112 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -417,7 +417,7 @@ const fetchStatus = ({ id, credentials }) => {
 }
 
 const fetchStatusSource = ({ id, credentials }) => {
-  let url = MASTODON_STATUS_SOURCE_URL(id)
+  const url = MASTODON_STATUS_SOURCE_URL(id)
   return fetch(url, { headers: authHeaders(credentials) })
     .then((data) => {
       if (data.ok) {
@@ -430,7 +430,7 @@ const fetchStatusSource = ({ id, credentials }) => {
 }
 
 const fetchStatusHistory = ({ status, credentials }) => {
-  let url = MASTODON_STATUS_HISTORY_URL(status.id)
+  const url = MASTODON_STATUS_HISTORY_URL(status.id)
   return promisedRequest({ url, credentials })
     .then((data) => {
       data.reverse()
@@ -767,7 +767,7 @@ const editStatus = ({
     })
   }
 
-  let putHeaders = authHeaders(credentials)
+  const putHeaders = authHeaders(credentials)
 
   return fetch(MASTODON_STATUS_URL(id), {
     body: form,
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index c00e9796..c1b2ffac 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -378,7 +378,7 @@ export const parseStatus = (data) => {
   output.favoritedBy = []
   output.rebloggedBy = []
 
-  if (data.hasOwnProperty('originalStatus')) {
+  if (Object.prototype.hasOwnProperty.call(data, 'originalStatus')) {
     Object.assign(output, data.originalStatus)
   }
 
-- 
cgit v1.2.3-70-g09d2


From 04e62df377fdd2ea563f58dcd23ea8048fc1c140 Mon Sep 17 00:00:00 2001
From: Sean King <seanking2919@protonmail.com>
Date: Tue, 2 Aug 2022 23:19:25 -0600
Subject: Allow for template inside Timeago component that shows unless the
 time string is 'just now'

---
 src/components/status/status.vue   | 16 ++++++----------
 src/components/timeago/timeago.vue | 26 ++++++++++++++++++--------
 2 files changed, 24 insertions(+), 18 deletions(-)

(limited to 'src/components/status/status.vue')

diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 5ddb94b4..8036ddf4 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -336,16 +336,12 @@
                 tag="span"
               >
                 <template #time>
-                  <i18n-t
-                    keypath="time.in_past"
-                    tag="span"
-                  >
-                    <Timeago
-                      :time="status.edited_at"
-                      :auto-update="60"
-                      :long-format="true"
-                    />
-                  </i18n-t>
+                  <Timeago
+                    template-key="time.in_past"
+                    :time="status.edited_at"
+                    :auto-update="60"
+                    :long-format="true"
+                  />
                 </template>
               </i18n-t>
             </div>
diff --git a/src/components/timeago/timeago.vue b/src/components/timeago/timeago.vue
index fce9605b..b5f49515 100644
--- a/src/components/timeago/timeago.vue
+++ b/src/components/timeago/timeago.vue
@@ -3,7 +3,7 @@
     :datetime="time"
     :title="localeDateString"
   >
-    {{ $tc(relativeTime.key, relativeTime.num, [relativeTime.num]) }}
+    {{ relativeTimeString }}
   </time>
 </template>
 
@@ -13,7 +13,7 @@ import localeService from 'src/services/locale/locale.service.js'
 
 export default {
   name: 'Timeago',
-  props: ['time', 'autoUpdate', 'longFormat', 'nowThreshold'],
+  props: ['time', 'autoUpdate', 'longFormat', 'nowThreshold', 'templateKey'],
   data () {
     return {
       relativeTime: { key: 'time.now', num: 0 },
@@ -26,21 +26,31 @@ export default {
       return typeof this.time === 'string'
         ? new Date(Date.parse(this.time)).toLocaleString(browserLocale)
         : this.time.toLocaleString(browserLocale)
+    },
+    relativeTimeString () {
+      const timeString = this.$i18n.tc(this.relativeTime.key, this.relativeTime.num, [this.relativeTime.num])
+
+      if (typeof this.templateKey === 'string' && this.relativeTime.key !== 'time.now') {
+        return this.$i18n.t(this.templateKey, [timeString])
+      }
+
+      return timeString
     }
   },
-  created () {
-    this.refreshRelativeTimeObject()
-  },
-  unmounted () {
-    clearTimeout(this.interval)
-  },
   watch: {
     time (newVal, oldVal) {
       if (oldVal !== newVal) {
+        clearTimeout(this.interval)
         this.refreshRelativeTimeObject()
       }
     }
   },
+  created () {
+    this.refreshRelativeTimeObject()
+  },
+  unmounted () {
+    clearTimeout(this.interval)
+  },
   methods: {
     refreshRelativeTimeObject () {
       const nowThreshold = typeof this.nowThreshold === 'number' ? this.nowThreshold : 1
-- 
cgit v1.2.3-70-g09d2


From 0a79a747730bb4a10eb2544412dab68a10602240 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Mon, 29 Aug 2022 18:46:41 -0400
Subject: Use dedicated indicator for non-ascii domain names

---
 src/components/basic_user_card/basic_user_card.js  |  4 ++-
 src/components/basic_user_card/basic_user_card.vue |  8 ++---
 src/components/emoji_input/emoji_input.js          |  4 ++-
 src/components/emoji_input/emoji_input.vue         | 16 ++++++++-
 src/components/emoji_input/suggestor.js            | 11 ++++---
 src/components/mention_link/mention_link.js        |  2 ++
 src/components/mention_link/mention_link.vue       |  3 ++
 src/components/notification/notification.js        |  4 ++-
 src/components/notification/notification.vue       | 21 ++++++------
 src/components/status/status.js                    |  4 ++-
 src/components/status/status.vue                   | 16 ++++-----
 .../unicode_domain_indicator.vue                   | 26 +++++++++++++++
 src/components/user_card/user_card.js              |  4 ++-
 src/components/user_card/user_card.vue             |  9 ++---
 src/components/user_link/user_link.vue             | 38 ++++++++++++++++++++++
 .../user_list_popover/user_list_popover.js         |  2 ++
 .../user_list_popover/user_list_popover.vue        |  2 +-
 .../user_reporting_modal/user_reporting_modal.js   |  4 ++-
 .../user_reporting_modal/user_reporting_modal.vue  | 10 ++++--
 src/i18n/en.json                                   |  3 ++
 .../entity_normalizer/entity_normalizer.service.js |  6 ++--
 .../entity_normalizer/entity_normalizer.spec.js    |  3 +-
 22 files changed, 151 insertions(+), 49 deletions(-)
 create mode 100644 src/components/unicode_domain_indicator/unicode_domain_indicator.vue
 create mode 100644 src/components/user_link/user_link.vue

(limited to 'src/components/status/status.vue')

diff --git a/src/components/basic_user_card/basic_user_card.js b/src/components/basic_user_card/basic_user_card.js
index 8b1a2c38..31de2d75 100644
--- a/src/components/basic_user_card/basic_user_card.js
+++ b/src/components/basic_user_card/basic_user_card.js
@@ -1,5 +1,6 @@
 import UserPopover from '../user_popover/user_popover.vue'
 import UserAvatar from '../user_avatar/user_avatar.vue'
+import UserLink from '../user_link/user_link.vue'
 import RichContent from 'src/components/rich_content/rich_content.jsx'
 import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
 
@@ -10,7 +11,8 @@ const BasicUserCard = {
   components: {
     UserPopover,
     UserAvatar,
-    RichContent
+    RichContent,
+    UserLink
   },
   methods: {
     userProfileLink (user) {
diff --git a/src/components/basic_user_card/basic_user_card.vue b/src/components/basic_user_card/basic_user_card.vue
index 9cca7840..418de926 100644
--- a/src/components/basic_user_card/basic_user_card.vue
+++ b/src/components/basic_user_card/basic_user_card.vue
@@ -30,12 +30,10 @@
         />
       </div>
       <div>
-        <router-link
+        <user-link
           class="basic-user-card-screen-name"
-          :to="userProfileLink(user)"
-        >
-          @{{ user.screen_name_ui }}
-        </router-link>
+          :user="user"
+        />
       </div>
       <slot />
     </div>
diff --git a/src/components/emoji_input/emoji_input.js b/src/components/emoji_input/emoji_input.js
index 5ba3907f..b664d6b3 100644
--- a/src/components/emoji_input/emoji_input.js
+++ b/src/components/emoji_input/emoji_input.js
@@ -1,5 +1,6 @@
 import Completion from '../../services/completion/completion.js'
 import EmojiPicker from '../emoji_picker/emoji_picker.vue'
+import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue'
 import { take } from 'lodash'
 import { findOffset } from '../../services/offset_finder/offset_finder.service.js'
 
@@ -120,7 +121,8 @@ const EmojiInput = {
     }
   },
   components: {
-    EmojiPicker
+    EmojiPicker,
+    UnicodeDomainIndicator
   },
   computed: {
     padEmoji () {
diff --git a/src/components/emoji_input/emoji_input.vue b/src/components/emoji_input/emoji_input.vue
index 7d95ab7e..81b81913 100644
--- a/src/components/emoji_input/emoji_input.vue
+++ b/src/components/emoji_input/emoji_input.vue
@@ -50,7 +50,21 @@
             <span v-else>{{ suggestion.replacement }}</span>
           </span>
           <div class="label">
-            <span class="displayText">{{ suggestion.displayText }}</span>
+            <span
+              v-if="suggestion.user"
+              class="displayText"
+            >
+              {{ suggestion.displayText }}<UnicodeDomainIndicator
+                :user="suggestion.user"
+                :at="false"
+              />
+            </span>
+            <span
+              v-if="!suggestion.user"
+              class="displayText"
+            >
+              {{ suggestion.displayText }}
+            </span>
             <span class="detailText">{{ suggestion.detailText }}</span>
           </div>
         </div>
diff --git a/src/components/emoji_input/suggestor.js b/src/components/emoji_input/suggestor.js
index e8efbd1e..0ddb4d68 100644
--- a/src/components/emoji_input/suggestor.js
+++ b/src/components/emoji_input/suggestor.js
@@ -116,11 +116,12 @@ export const suggestUsers = ({ dispatch, state }) => {
 
       return diff + nameAlphabetically + screenNameAlphabetically
       /* eslint-disable camelcase */
-    }).map(({ screen_name, screen_name_ui, name, profile_image_url_original }) => ({
-      displayText: screen_name_ui,
-      detailText: name,
-      imageUrl: profile_image_url_original,
-      replacement: '@' + screen_name + ' '
+    }).map((user) => ({
+      user,
+      displayText: user.screen_name_ui,
+      detailText: user.name,
+      imageUrl: user.profile_image_url_original,
+      replacement: '@' + user.screen_name + ' '
     }))
     /* eslint-enable camelcase */
 
diff --git a/src/components/mention_link/mention_link.js b/src/components/mention_link/mention_link.js
index 4a74fbe2..6515bd11 100644
--- a/src/components/mention_link/mention_link.js
+++ b/src/components/mention_link/mention_link.js
@@ -2,6 +2,7 @@ import generateProfileLink from 'src/services/user_profile_link_generator/user_p
 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 {
@@ -16,6 +17,7 @@ const MentionLink = {
   name: 'MentionLink',
   components: {
     UserAvatar,
+    UnicodeDomainIndicator,
     UserPopover: defineAsyncComponent(() => import('../user_popover/user_popover.vue'))
   },
   props: {
diff --git a/src/components/mention_link/mention_link.vue b/src/components/mention_link/mention_link.vue
index 3af502ef..869a3257 100644
--- a/src/components/mention_link/mention_link.vue
+++ b/src/components/mention_link/mention_link.vue
@@ -47,6 +47,9 @@
             class="serverName"
             :class="{ '-faded': shouldFadeDomain }"
             v-html="'@' + serverName"
+          /><UnicodeDomainIndicator
+            v-if="shouldShowFullUserName"
+            :user="user"
           />
           </span>
           <span
diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js
index f60a1a6a..ddba560e 100644
--- a/src/components/notification/notification.js
+++ b/src/components/notification/notification.js
@@ -5,6 +5,7 @@ import UserAvatar from '../user_avatar/user_avatar.vue'
 import UserCard from '../user_card/user_card.vue'
 import Timeago from '../timeago/timeago.vue'
 import Report from '../report/report.vue'
+import UserLink from '../user_link/user_link.vue'
 import RichContent from 'src/components/rich_content/rich_content.jsx'
 import UserPopover from '../user_popover/user_popover.vue'
 import { isStatusNotification } from '../../services/notification_utils/notification_utils.js'
@@ -50,7 +51,8 @@ const Notification = {
     Status,
     Report,
     RichContent,
-    UserPopover
+    UserPopover,
+    UserLink
   },
   methods: {
     toggleUserExpanded () {
diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue
index 6a5417b3..26b174ff 100644
--- a/src/components/notification/notification.vue
+++ b/src/components/notification/notification.vue
@@ -11,9 +11,10 @@
       class="Notification container -muted"
     >
       <small>
-        <router-link :to="userProfileLink">
-          {{ notification.from_profile.screen_name_ui }}
-        </router-link>
+        <user-link
+          :user="notification.from_profile"
+          :at="false"
+        />
       </small>
       <button
         class="button-unstyled unmute"
@@ -174,12 +175,10 @@
           v-if="notification.type === 'follow' || notification.type === 'follow_request'"
           class="follow-text"
         >
-          <router-link
-            :to="userProfileLink"
+          <user-link
             class="follow-name"
-          >
-            @{{ notification.from_profile.screen_name_ui }}
-          </router-link>
+            :user="notification.from_profile"
+          />
           <div
             v-if="notification.type === 'follow_request'"
             style="white-space: nowrap;"
@@ -210,9 +209,9 @@
           v-else-if="notification.type === 'move'"
           class="move-text"
         >
-          <router-link :to="targetUserProfileLink">
-            @{{ notification.target.screen_name_ui }}
-          </router-link>
+          <user-link
+            :user="notification.target"
+          />
         </div>
         <Report
           v-else-if="notification.type === 'pleroma:report'"
diff --git a/src/components/status/status.js b/src/components/status/status.js
index 384063a7..19356664 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -13,6 +13,7 @@ import StatusPopover from '../status_popover/status_popover.vue'
 import UserPopover from '../user_popover/user_popover.vue'
 import UserListPopover from '../user_list_popover/user_list_popover.vue'
 import EmojiReactions from '../emoji_reactions/emoji_reactions.vue'
+import UserLink from '../user_link/user_link.vue'
 import MentionsLine from 'src/components/mentions_line/mentions_line.vue'
 import MentionLink from 'src/components/mention_link/mention_link.vue'
 import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
@@ -115,7 +116,8 @@ const Status = {
     RichContent,
     MentionLink,
     MentionsLine,
-    UserPopover
+    UserPopover,
+    UserLink
   },
   props: [
     'statusoid',
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 967a966c..91f5fffa 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -25,9 +25,10 @@
             class="fa-scale-110 fa-old-padding repeat-icon"
             icon="retweet"
           />
-          <router-link :to="userProfileLink">
-            {{ status.user.screen_name_ui }}
-          </router-link>
+          <user-link
+            :user="status.user"
+            :at="false"
+          />
         </small>
         <small
           v-if="showReasonMutedThread"
@@ -164,13 +165,12 @@
                 >
                   {{ status.user.name }}
                 </h4>
-                <router-link
+                <user-link
                   class="account-name"
                   :title="status.user.screen_name_ui"
-                  :to="userProfileLink"
-                >
-                  {{ status.user.screen_name_ui }}
-                </router-link>
+                  :user="status.user"
+                  :at="false"
+                />
                 <img
                   v-if="!!(status.user && status.user.favicon)"
                   class="status-favicon"
diff --git a/src/components/unicode_domain_indicator/unicode_domain_indicator.vue b/src/components/unicode_domain_indicator/unicode_domain_indicator.vue
new file mode 100644
index 00000000..8f35245f
--- /dev/null
+++ b/src/components/unicode_domain_indicator/unicode_domain_indicator.vue
@@ -0,0 +1,26 @@
+<template>
+  <FAIcon
+    v-if="user && user.screen_name_ui_contains_non_ascii"
+    icon="code"
+    :title="$t('unicode_domain_indicator.tooltip')"
+  />
+</template>
+
+<script>
+import { library } from '@fortawesome/fontawesome-svg-core'
+import {
+  faCode
+} from '@fortawesome/free-solid-svg-icons'
+
+library.add(
+  faCode
+)
+
+const UnicodeDomainIndicator = {
+  props: {
+    user: Object
+  }
+}
+
+export default UnicodeDomainIndicator
+</script>
diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js
index 4c81e2c7..37458ba2 100644
--- a/src/components/user_card/user_card.js
+++ b/src/components/user_card/user_card.js
@@ -5,6 +5,7 @@ import FollowButton from '../follow_button/follow_button.vue'
 import ModerationTools from '../moderation_tools/moderation_tools.vue'
 import AccountActions from '../account_actions/account_actions.vue'
 import Select from '../select/select.vue'
+import UserLink from '../user_link/user_link.vue'
 import RichContent from 'src/components/rich_content/rich_content.jsx'
 import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
 import { mapGetters } from 'vuex'
@@ -134,7 +135,8 @@ export default {
     ProgressButton,
     FollowButton,
     Select,
-    RichContent
+    RichContent,
+    UserLink
   },
   methods: {
     muteUser () {
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index ace89c51..b84ff27d 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -106,13 +106,10 @@
               </button>
             </div>
             <div class="bottom-line">
-              <router-link
+              <user-link
                 class="user-screen-name"
-                :title="user.screen_name_ui"
-                :to="userProfileLink(user)"
-              >
-                @{{ user.screen_name_ui }}
-              </router-link>
+                :user="user"
+              />
               <template v-if="!hideBio">
                 <span
                   v-if="user.deactivated"
diff --git a/src/components/user_link/user_link.vue b/src/components/user_link/user_link.vue
new file mode 100644
index 00000000..efd96e12
--- /dev/null
+++ b/src/components/user_link/user_link.vue
@@ -0,0 +1,38 @@
+<template>
+  <router-link
+    :title="user.screen_name_ui"
+    :to="userProfileLink(user)"
+  >
+    {{ at ? '@' : '' }}{{ user.screen_name_ui }}<UnicodeDomainIndicator
+      :user="user"
+    />
+  </router-link>
+</template>
+
+<script>
+import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue'
+import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
+
+const UserLink = {
+  props: {
+    user: Object,
+    at: {
+      type: Boolean,
+      default: true
+    }
+  },
+  components: {
+    UnicodeDomainIndicator
+  },
+  methods: {
+    userProfileLink (user) {
+      return generateProfileLink(
+        user.id, user.screen_name,
+        this.$store.state.instance.restrictedNicknames
+      )
+    }
+  }
+}
+
+export default UserLink
+</script>
diff --git a/src/components/user_list_popover/user_list_popover.js b/src/components/user_list_popover/user_list_popover.js
index e24eb9f7..046e0abd 100644
--- a/src/components/user_list_popover/user_list_popover.js
+++ b/src/components/user_list_popover/user_list_popover.js
@@ -1,5 +1,6 @@
 import { defineAsyncComponent } from 'vue'
 import RichContent from 'src/components/rich_content/rich_content.jsx'
+import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue'
 
 import { library } from '@fortawesome/fontawesome-svg-core'
 import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'
@@ -15,6 +16,7 @@ const UserListPopover = {
   ],
   components: {
     RichContent,
+    UnicodeDomainIndicator,
     Popover: defineAsyncComponent(() => import('../popover/popover.vue')),
     UserAvatar: defineAsyncComponent(() => import('../user_avatar/user_avatar.vue'))
   },
diff --git a/src/components/user_list_popover/user_list_popover.vue b/src/components/user_list_popover/user_list_popover.vue
index a3ce54c3..635dc7f6 100644
--- a/src/components/user_list_popover/user_list_popover.vue
+++ b/src/components/user_list_popover/user_list_popover.vue
@@ -29,7 +29,7 @@
                 :emoji="user.emoji"
               />
               <!-- eslint-enable vue/no-v-html -->
-              <span class="user-list-screen-name">{{ user.screen_name_ui }}</span>
+              <span class="user-list-screen-name">{{ user.screen_name_ui }}</span><UnicodeDomainIndicator :user="user" />
             </div>
           </div>
         </template>
diff --git a/src/components/user_reporting_modal/user_reporting_modal.js b/src/components/user_reporting_modal/user_reporting_modal.js
index 85ffc661..67fde084 100644
--- a/src/components/user_reporting_modal/user_reporting_modal.js
+++ b/src/components/user_reporting_modal/user_reporting_modal.js
@@ -2,13 +2,15 @@ import Status from '../status/status.vue'
 import List from '../list/list.vue'
 import Checkbox from '../checkbox/checkbox.vue'
 import Modal from '../modal/modal.vue'
+import UserLink from '../user_link/user_link.vue'
 
 const UserReportingModal = {
   components: {
     Status,
     List,
     Checkbox,
-    Modal
+    Modal,
+    UserLink
   },
   data () {
     return {
diff --git a/src/components/user_reporting_modal/user_reporting_modal.vue b/src/components/user_reporting_modal/user_reporting_modal.vue
index 429a66e2..8c42ab7b 100644
--- a/src/components/user_reporting_modal/user_reporting_modal.vue
+++ b/src/components/user_reporting_modal/user_reporting_modal.vue
@@ -5,9 +5,13 @@
   >
     <div class="user-reporting-panel panel">
       <div class="panel-heading">
-        <div class="title">
-          {{ $t('user_reporting.title', [user.screen_name_ui]) }}
-        </div>
+        <i18n-t
+          tag="div"
+          keypath="user_reporting.title"
+          class="title"
+        >
+          <UserLink :user="user" />
+        </i18n-t>
       </div>
       <div class="panel-body">
         <div class="user-reporting-panel-left">
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 91722d9a..4ce56678 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -1006,5 +1006,8 @@
     "update_changelog": "For more details on what's changed, see {theFullChangelog}.",
     "update_changelog_here": "the full changelog",
     "art_by": "Art by {linkToArtist}"
+  },
+  "unicode_domain_indicator": {
+    "tooltip": "This domain contains non-ascii characters."
   }
 }
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index e9cbcfe6..ce316832 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -214,12 +214,14 @@ export const parseUser = (data) => {
   output.screen_name_ui = output.screen_name
   if (output.screen_name && output.screen_name.includes('@')) {
     const parts = output.screen_name.split('@')
-    let unicodeDomain = punycode.toUnicode(parts[1])
+    const unicodeDomain = punycode.toUnicode(parts[1])
     if (unicodeDomain !== parts[1]) {
       // Add some identifier so users can potentially spot spoofing attempts:
       // lain.com and xn--lin-6cd.com would appear identical otherwise.
-      unicodeDomain = '🌏' + unicodeDomain
+      output.screen_name_ui_contains_non_ascii = true
       output.screen_name_ui = [parts[0], unicodeDomain].join('@')
+    } else {
+      output.screen_name_ui_contains_non_ascii = false
     }
   }
 
diff --git a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js
index 98bb05a8..3923596b 100644
--- a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js
+++ b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js
@@ -269,7 +269,8 @@ describe('API Entities normalizer', () => {
     it('converts IDN to unicode and marks it as internatonal', () => {
       const user = makeMockUserMasto({ acct: 'lain@xn--lin-6cd.com' })
 
-      expect(parseUser(user)).to.have.property('screen_name_ui').that.equal('lain@🌏lаin.com')
+      expect(parseUser(user)).to.have.property('screen_name_ui').that.equal('lain@lаin.com')
+      expect(parseUser(user)).to.have.property('screen_name_ui_contains_non_ascii').that.equal(true)
     })
   })
 
-- 
cgit v1.2.3-70-g09d2

