aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenry Jameson <me@hjkos.com>2022-07-31 11:44:15 +0300
committerHenry Jameson <me@hjkos.com>2022-07-31 11:44:15 +0300
commit1cf7af33741ee43aff9e597f0a69f62f7d660cf6 (patch)
tree75eea24b29b4204b57e38aec8223e91a1f1526fe
parent0b88c56aa674ad19be7e7e883a3687ec89569940 (diff)
parent36aae1635ad370ecf4d22ae6d62cbbba6af19fd3 (diff)
Merge branch 'disjointed-popovers' into eslint-update
* disjointed-popovers: (56 commits) fix typo fix errors in console pinned no longer needed popover stack add stay-on-click prop to solve case of clicking user avatar in status popover fix settings tooltips vertical nudge for popovers, especially for overlay-centers ones make user popover options expert use same sizing for timeline dropdown as in the main nav fix avatar not zooming in profile page fix spacing in mentionsline add popovers to chats fix avatar not closing, add option to put popovers next to avatar instead of over it fix the incorrect rounding in nav list re-unfuck the timeline popover Revert "unify styling of timelines dropdown with other dropdown menus" close on avatar click again, add zooming as option fix basicusercard make hover popovers less annoying to close move tooltips setting ...
-rw-r--r--CHANGELOG.md12
-rw-r--r--src/App.js3
-rw-r--r--src/App.scss11
-rw-r--r--src/App.vue3
-rw-r--r--src/boot/after_store.js3
-rw-r--r--src/components/basic_user_card/basic_user_card.js12
-rw-r--r--src/components/basic_user_card/basic_user_card.vue31
-rw-r--r--src/components/chat_message/chat_message.js8
-rw-r--r--src/components/chat_message/chat_message.vue8
-rw-r--r--src/components/chat_title/chat_title.js10
-rw-r--r--src/components/chat_title/chat_title.vue6
-rw-r--r--src/components/desktop_nav/desktop_nav.scss1
-rw-r--r--src/components/desktop_nav/desktop_nav.vue2
-rw-r--r--src/components/emoji_picker/emoji_picker.scss3
-rw-r--r--src/components/extra_buttons/extra_buttons.js3
-rw-r--r--src/components/extra_buttons/extra_buttons.vue50
-rw-r--r--src/components/global_notice_list/global_notice_list.vue2
-rw-r--r--src/components/media_modal/media_modal.vue2
-rw-r--r--src/components/mention_link/mention_link.js24
-rw-r--r--src/components/mention_link/mention_link.scss29
-rw-r--r--src/components/mention_link/mention_link.vue84
-rw-r--r--src/components/mentions_line/mentions_line.vue3
-rw-r--r--src/components/mobile_nav/mobile_nav.vue6
-rw-r--r--src/components/modal/modal.vue5
-rw-r--r--src/components/nav_panel/nav_panel.vue2
-rw-r--r--src/components/notification/notification.js4
-rw-r--r--src/components/notification/notification.vue25
-rw-r--r--src/components/notifications/notifications.js10
-rw-r--r--src/components/popover/popover.js221
-rw-r--r--src/components/popover/popover.vue48
-rw-r--r--src/components/react_button/react_button.vue5
-rw-r--r--src/components/settings_modal/helpers/modified_indicator.vue10
-rw-r--r--src/components/settings_modal/helpers/server_side_indicator.vue10
-rw-r--r--src/components/settings_modal/tabs/general_tab.vue30
-rw-r--r--src/components/shout_panel/shout_panel.vue2
-rw-r--r--src/components/side_drawer/side_drawer.vue2
-rw-r--r--src/components/status/status.js6
-rw-r--r--src/components/status/status.vue32
-rw-r--r--src/components/status_popover/status_popover.js7
-rw-r--r--src/components/status_popover/status_popover.vue4
-rw-r--r--src/components/timeline_menu/timeline_menu.vue50
-rw-r--r--src/components/user_card/user_card.js30
-rw-r--r--src/components/user_card/user_card.scss51
-rw-r--r--src/components/user_card/user_card.vue50
-rw-r--r--src/components/user_popover/user_popover.js23
-rw-r--r--src/components/user_popover/user_popover.vue33
-rw-r--r--src/components/user_profile/user_profile.vue2
-rw-r--r--src/i18n/en.json4
-rw-r--r--src/modules/config.js2
-rw-r--r--test/unit/specs/components/rich_content.spec.js28
50 files changed, 656 insertions, 356 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fac68ac0..b7eea727 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,17 +16,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Attachments are ALWAYS in same order as user uploaded, no more "videos first"
- Attachment description is prefilled with backend-provided default when uploading
- Proper visual feedback that next image is loading when browsing
+- UI no longer lags when switching between mobile and desktop mode
+- Popovers no longer constrained by DOM hierarchy, shouldn't be cut off by anything
+- "Always show mobile button" is working now
### Changed
+- Using Vue 3 now
- (You)s are optional (opt-in) now, bolding your nickname is also optional (opt-out)
- User highlight background now also covers the `@`
- Reverted back to textual `@`, svg version is opt-in.
-- Settings window has been throughly rearranged to make make more sense and make navication settings easier.
+- Settings window has been thoroughly rearranged to make more sense and make navigation settings easier.
- Uploaded attachments are uniform with displayed attachments
- Flash is watchable in media-modal (takes up nearly full screen though due to sizing issues)
- Notifications about likes/repeats/emoji reacts are now minimized so they always take up same amount of space irrelevant to size of post.
+- Slight width/spacing adjustments
+- More sizing stuff is font-size dependent now
+- Scrollbars are styled/colorized now
+- Scrollbars are toggleable (for stuff that didn't have visible scrollbars before) (opt-in)
### Added
+- 3 column mode: only enables when there's space for it (opt-out, customizable)
- Options to show domains in mentions
- Option to show user avatars in mention links (opt-in)
- Option to disable the tooltip for mentions
@@ -37,6 +46,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Media modal now also displays description and counter position in gallery (i.e. 1/5)
- Ability to rearrange order of attachments when uploading
- Enabled users to zoom and pan images in media viewer with mouse and touch
+- Timelines/panels and conversations have sticky headers now
- Added frontend ui for account migration
diff --git a/src/App.js b/src/App.js
index f01f8788..d5967685 100644
--- a/src/App.js
+++ b/src/App.js
@@ -4,7 +4,6 @@ import InstanceSpecificPanel from './components/instance_specific_panel/instance
import FeaturesPanel from './components/features_panel/features_panel.vue'
import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_panel.vue'
import ShoutPanel from './components/shout_panel/shout_panel.vue'
-import SettingsModal from './components/settings_modal/settings_modal.vue'
import MediaModal from './components/media_modal/media_modal.vue'
import SideDrawer from './components/side_drawer/side_drawer.vue'
import MobilePostStatusButton from './components/mobile_post_status_button/mobile_post_status_button.vue'
@@ -32,7 +31,7 @@ export default {
MobilePostStatusButton,
MobileNav,
DesktopNav,
- SettingsModal,
+ SettingsModal: defineAsyncComponent(() => import('./components/settings_modal/settings_modal.vue')),
UserReportingModal,
PostStatusModal,
GlobalNoticeList
diff --git a/src/App.scss b/src/App.scss
index 7e6d0dfc..ab025d63 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -4,6 +4,13 @@
:root {
--navbar-height: 3.5rem;
--post-line-height: 1.4;
+ // Z-Index stuff
+ --ZI_media_modal: 90000;
+ --ZI_modals_popovers: 85000;
+ --ZI_modals: 80000;
+ --ZI_navbar_popovers: 75000;
+ --ZI_navbar: 70000;
+ --ZI_popovers: 60000;
}
html {
@@ -117,7 +124,7 @@ i[class*=icon-],
}
nav {
- z-index: 1000;
+ z-index: var(--ZI_navbar);
color: var(--topBarText);
background-color: $fallback--fg;
background-color: var(--topBar, $fallback--fg);
@@ -828,7 +835,7 @@ option {
// Vue transitions
.fade-enter-active,
.fade-leave-active {
- transition: opacity 0.2s;
+ transition: opacity 0.3s;
}
.fade-enter-from,
diff --git a/src/App.vue b/src/App.vue
index 21f6f686..7d4a8e1e 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -42,7 +42,7 @@
</div>
<div id="notifs-column" class="column -scrollable" :class="{ '-show-scrollbar': showScrollbars }"/>
</div>
- <media-modal />
+ <MediaModal />
<shout-panel
v-if="currentUser && shout && !hideShoutbox"
:floating="true"
@@ -55,6 +55,7 @@
<SettingsModal />
<div id="modal" />
<GlobalNoticeList />
+ <div id="popovers" />
</div>
</template>
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index f655c38f..894a68e1 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -396,6 +396,9 @@ const afterStoreSetup = async ({ store, i18n }) => {
app.component('FAIcon', FontAwesomeIcon)
app.component('FALayers', FontAwesomeLayers)
+ // remove after vue 3.3
+ app.config.unwrapInjectedRef = true
+
app.mount('#app')
return app
diff --git a/src/components/basic_user_card/basic_user_card.js b/src/components/basic_user_card/basic_user_card.js
index 8f41e2fb..8b1a2c38 100644
--- a/src/components/basic_user_card/basic_user_card.js
+++ b/src/components/basic_user_card/basic_user_card.js
@@ -1,4 +1,4 @@
-import UserCard from '../user_card/user_card.vue'
+import UserPopover from '../user_popover/user_popover.vue'
import UserAvatar from '../user_avatar/user_avatar.vue'
import RichContent from 'src/components/rich_content/rich_content.jsx'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
@@ -7,20 +7,12 @@ const BasicUserCard = {
props: [
'user'
],
- data () {
- return {
- userExpanded: false
- }
- },
components: {
- UserCard,
+ UserPopover,
UserAvatar,
RichContent
},
methods: {
- toggleUserExpanded () {
- this.userExpanded = !this.userExpanded
- },
userProfileLink (user) {
return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames)
}
diff --git a/src/components/basic_user_card/basic_user_card.vue b/src/components/basic_user_card/basic_user_card.vue
index eeca7828..effd9268 100644
--- a/src/components/basic_user_card/basic_user_card.vue
+++ b/src/components/basic_user_card/basic_user_card.vue
@@ -1,24 +1,19 @@
<template>
<div class="basic-user-card">
- <router-link :to="userProfileLink(user)">
- <UserAvatar
- class="avatar"
- :user="user"
- @click.prevent="toggleUserExpanded"
- />
+ <router-link @click.prevent :to="userProfileLink(user)">
+ <UserPopover
+ :userId="user.id"
+ :overlayCenters="true"
+ overlayCentersSelector=".avatar"
+ >
+ <UserAvatar
+ class="user-avatar avatar"
+ :user="user"
+ @click.prevent
+ />
+ </UserPopover>
</router-link>
<div
- v-if="userExpanded"
- class="basic-user-card-expanded-content"
- >
- <UserCard
- :user-id="user.id"
- :rounded="true"
- :bordered="true"
- />
- </div>
- <div
- v-else
class="basic-user-card-collapsed-content"
>
<div
@@ -53,6 +48,8 @@
margin: 0;
padding: 0.6em 1em;
+ --emoji-size: 14px;
+
&-collapsed-content {
margin-left: 0.7em;
text-align: left;
diff --git a/src/components/chat_message/chat_message.js b/src/components/chat_message/chat_message.js
index 5bac7736..ebe09814 100644
--- a/src/components/chat_message/chat_message.js
+++ b/src/components/chat_message/chat_message.js
@@ -6,7 +6,7 @@ import Gallery from '../gallery/gallery.vue'
import LinkPreview from '../link-preview/link-preview.vue'
import StatusContent from '../status_content/status_content.vue'
import ChatMessageDate from '../chat_message_date/chat_message_date.vue'
-import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
+import { defineAsyncComponent } from 'vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faTimes,
@@ -35,7 +35,8 @@ const ChatMessage = {
UserAvatar,
Gallery,
LinkPreview,
- ChatMessageDate
+ ChatMessageDate,
+ UserPopover: defineAsyncComponent(() => import('../user_popover/user_popover.vue'))
},
computed: {
// Returns HH:MM (hours and minutes) in local time.
@@ -49,9 +50,6 @@ const ChatMessage = {
message () {
return this.chatViewItem.data
},
- userProfileLink () {
- return generateProfileLink(this.author.id, this.author.screen_name, this.$store.state.instance.restrictedNicknames)
- },
isMessage () {
return this.chatViewItem.type === 'message'
},
diff --git a/src/components/chat_message/chat_message.vue b/src/components/chat_message/chat_message.vue
index d62b831d..9b823f7d 100644
--- a/src/components/chat_message/chat_message.vue
+++ b/src/components/chat_message/chat_message.vue
@@ -14,16 +14,16 @@
v-if="!isCurrentUser"
class="avatar-wrapper"
>
- <router-link
+ <UserPopover
v-if="chatViewItem.isHead"
- :to="userProfileLink"
+ :userId="author.id"
>
<UserAvatar
:compact="true"
:better-shadow="betterShadow"
:user="author"
/>
- </router-link>
+ </UserPopover>
</div>
<div class="chat-message-inner">
<div
@@ -44,7 +44,7 @@
<Popover
trigger="click"
placement="top"
- :bound-to-selector="isCurrentUser ? '' : '.scrollable-message-list'"
+ bound-to-selector=".chat-view-inner"
:bound-to="{ x: 'container' }"
:margin="popoverMarginStyle"
@show="menuOpened = true"
diff --git a/src/components/chat_title/chat_title.js b/src/components/chat_title/chat_title.js
index f6e299ad..b8721126 100644
--- a/src/components/chat_title/chat_title.js
+++ b/src/components/chat_title/chat_title.js
@@ -1,12 +1,13 @@
-import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import UserAvatar from '../user_avatar/user_avatar.vue'
import RichContent from 'src/components/rich_content/rich_content.jsx'
+import { defineAsyncComponent } from 'vue'
export default {
name: 'ChatTitle',
components: {
UserAvatar,
- RichContent
+ RichContent,
+ UserPopover: defineAsyncComponent(() => import('../user_popover/user_popover.vue'))
},
props: [
'user', 'withAvatar'
@@ -18,10 +19,5 @@ export default {
htmlTitle () {
return this.user ? this.user.name_html : ''
}
- },
- methods: {
- getUserProfileLink (user) {
- return generateProfileLink(user.id, user.screen_name)
- }
}
}
diff --git a/src/components/chat_title/chat_title.vue b/src/components/chat_title/chat_title.vue
index 7f6aaaa4..22d0e7c4 100644
--- a/src/components/chat_title/chat_title.vue
+++ b/src/components/chat_title/chat_title.vue
@@ -3,16 +3,16 @@
class="chat-title"
:title="title"
>
- <router-link
+ <UserPopover
class="avatar-container"
v-if="withAvatar && user"
- :to="getUserProfileLink(user)"
+ :userId="user.id"
>
<UserAvatar
class="titlebar-avatar"
:user="user"
/>
- </router-link>
+ </UserPopover>
<RichContent
v-if="user"
class="username"
diff --git a/src/components/desktop_nav/desktop_nav.scss b/src/components/desktop_nav/desktop_nav.scss
index eddd9707..71202244 100644
--- a/src/components/desktop_nav/desktop_nav.scss
+++ b/src/components/desktop_nav/desktop_nav.scss
@@ -2,6 +2,7 @@
.DesktopNav {
width: 100%;
+ z-index: var(--ZI_navbar);
input {
color: var(--inputTopbarText, var(--inputText));
diff --git a/src/components/desktop_nav/desktop_nav.vue b/src/components/desktop_nav/desktop_nav.vue
index bab3ca81..f352c78c 100644
--- a/src/components/desktop_nav/desktop_nav.vue
+++ b/src/components/desktop_nav/desktop_nav.vue
@@ -38,7 +38,7 @@
/>
<button
class="button-unstyled nav-icon"
- @click.stop="openSettingsModal"
+ @click="openSettingsModal"
>
<FAIcon
fixed-width
diff --git a/src/components/emoji_picker/emoji_picker.scss b/src/components/emoji_picker/emoji_picker.scss
index 2055e02e..a2f17c51 100644
--- a/src/components/emoji_picker/emoji_picker.scss
+++ b/src/components/emoji_picker/emoji_picker.scss
@@ -7,7 +7,8 @@
right: 0;
left: 0;
margin: 0 !important;
- z-index: 100;
+ // TODO: actually use popover in emoji picker
+ z-index: var(--ZI_popovers);
background-color: $fallback--bg;
background-color: var(--popover, $fallback--bg);
color: $fallback--link;
diff --git a/src/components/extra_buttons/extra_buttons.js b/src/components/extra_buttons/extra_buttons.js
index dd45b6b9..2f534896 100644
--- a/src/components/extra_buttons/extra_buttons.js
+++ b/src/components/extra_buttons/extra_buttons.js
@@ -89,6 +89,9 @@ const ExtraButtons = {
canMute () {
return !!this.currentUser
},
+ canBookmark () {
+ return !!this.currentUser
+ },
statusLink () {
return `${this.$store.state.instance.server}${this.$router.resolve({ name: 'conversation', params: { id: this.status.id } }).href}`
}
diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue
index a3c3c767..2ea86201 100644
--- a/src/components/extra_buttons/extra_buttons.vue
+++ b/src/components/extra_buttons/extra_buttons.vue
@@ -51,28 +51,30 @@
icon="thumbtack"
/><span>{{ $t("status.unpin") }}</span>
</button>
- <button
- v-if="!status.bookmarked"
- class="button-default dropdown-item dropdown-item-icon"
- @click.prevent="bookmarkStatus"
- @click="close"
- >
- <FAIcon
- fixed-width
- :icon="['far', 'bookmark']"
- /><span>{{ $t("status.bookmark") }}</span>
- </button>
- <button
- v-if="status.bookmarked"
- class="button-default dropdown-item dropdown-item-icon"
- @click.prevent="unbookmarkStatus"
- @click="close"
- >
- <FAIcon
- fixed-width
- icon="bookmark"
- /><span>{{ $t("status.unbookmark") }}</span>
- </button>
+ <template v-if="canBookmark">
+ <button
+ v-if="!status.bookmarked"
+ class="button-default dropdown-item dropdown-item-icon"
+ @click.prevent="bookmarkStatus"
+ @click="close"
+ >
+ <FAIcon
+ fixed-width
+ :icon="['far', 'bookmark']"
+ /><span>{{ $t("status.bookmark") }}</span>
+ </button>
+ <button
+ v-if="status.bookmarked"
+ class="button-default dropdown-item dropdown-item-icon"
+ @click.prevent="unbookmarkStatus"
+ @click="close"
+ >
+ <FAIcon
+ fixed-width
+ icon="bookmark"
+ /><span>{{ $t("status.unbookmark") }}</span>
+ </button>
+ </template>
<button
v-if="canDelete"
class="button-default dropdown-item dropdown-item-icon"
@@ -119,12 +121,12 @@
</div>
</template>
<template v-slot:trigger>
- <button class="button-unstyled popover-trigger">
+ <span class="button-unstyled popover-trigger">
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="ellipsis-h"
/>
- </button>
+ </span>
</template>
</Popover>
</template>
diff --git a/src/components/global_notice_list/global_notice_list.vue b/src/components/global_notice_list/global_notice_list.vue
index ddc45b81..09904761 100644
--- a/src/components/global_notice_list/global_notice_list.vue
+++ b/src/components/global_notice_list/global_notice_list.vue
@@ -32,7 +32,7 @@
top: 50px;
width: 100%;
pointer-events: none;
- z-index: 1001;
+ z-index: var(--ZI_popovers);
display: flex;
flex-direction: column;
align-items: center;
diff --git a/src/components/media_modal/media_modal.vue b/src/components/media_modal/media_modal.vue
index 8b76aafb..d59055b3 100644
--- a/src/components/media_modal/media_modal.vue
+++ b/src/components/media_modal/media_modal.vue
@@ -121,7 +121,7 @@ $modal-view-button-icon-width: 3em;
$modal-view-button-icon-margin: 0.5em;
.modal-view.media-modal-view {
- z-index: 9000;
+ z-index: var(--ZI_media_modal);
flex-direction: column;
.modal-view-button-arrow,
diff --git a/src/components/mention_link/mention_link.js b/src/components/mention_link/mention_link.js
index 55eea195..4a74fbe2 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 { defineAsyncComponent } from 'vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faAt
@@ -14,7 +15,8 @@ library.add(
const MentionLink = {
name: 'MentionLink',
components: {
- UserAvatar
+ UserAvatar,
+ UserPopover: defineAsyncComponent(() => import('../user_popover/user_popover.vue'))
},
props: {
url: {
@@ -34,15 +36,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)
@@ -88,7 +105,8 @@ const MentionLink = {
return [
{
'-you': this.isYou && this.shouldBoldenYou,
- '-highlighted': this.highlight
+ '-highlighted': this.highlight,
+ '-has-selection': this.hasSelection
},
this.highlightType
]
@@ -110,7 +128,7 @@ const MentionLink = {
}
},
shouldShowTooltip () {
- return this.mergedConfig.mentionLinkShowTooltip && this.mergedConfig.mentionLinkDisplay === 'short' && this.isRemote
+ return this.mergedConfig.mentionLinkShowTooltip
},
shouldShowAvatar () {
return this.mergedConfig.mentionLinkShowAvatar
diff --git a/src/components/mention_link/mention_link.scss b/src/components/mention_link/mention_link.scss
index 1d856ff9..8b2af926 100644
--- a/src/components/mention_link/mention_link.scss
+++ b/src/components/mention_link/mention_link.scss
@@ -55,11 +55,14 @@
.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);
@@ -72,8 +75,7 @@
}
&.-striped {
- & .shortName,
- & .full {
+ & .shortName {
background-image:
repeating-linear-gradient(
135deg,
@@ -86,30 +88,29 @@
}
&.-solid {
- & .shortName,
- & .full {
+ .shortName {
background-image: linear-gradient(var(--____highlight-tintColor2), var(--____highlight-tintColor2));
}
}
&.-side {
- & .shortName,
- & .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);
}
+}
- .full .-faded {
- color: var(--faint, $fallback--faint);
- }
+.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 022f04c7..56da8e0f 100644
--- a/src/components/mention_link/mention_link.vue
+++ b/src/components/mention_link/mention_link.vue
@@ -9,66 +9,58 @@
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
+ :userId="user.id"
+ :disabled="!shouldShowTooltip"
>
- <a
- class="short button-unstyled"
- :class="{ '-with-tooltip': shouldShowTooltip }"
- :href="url"
- @click.prevent="onClick"
+ <span
+ v-if="user"
+ class="new"
+ :style="style"
+ :class="classnames"
>
- <!-- 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"
- />
- </span>
- <span
- v-if="isYou && shouldShowYous"
- :class="{ '-you': shouldBoldenYou }"
- > {{ ' ' + $t('status.you') }}</span>
- <!-- eslint-enable vue/no-v-html -->
- </a><span
- v-if="shouldShowTooltip"
- class="full popover-default"
- :class="[highlightType]"
- >
- <span
- class="userNameFull"
+ <a
+ class="short button-unstyled"
+ :class="{ '-with-tooltip': shouldShowTooltip }"
+ :href="url"
+ @click.prevent="onClick"
>
<!-- eslint-disable vue/no-v-html -->
- @<span
+ <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"
/>
+ </span>
+ <span
+ v-if="isYou && shouldShowYous"
+ :class="{ '-you': shouldBoldenYou }"
+ > {{ ' ' + $t('status.you') }}</span>
<!-- eslint-enable vue/no-v-html -->
+ </a><span class="full" ref="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>
diff --git a/src/components/mentions_line/mentions_line.vue b/src/components/mentions_line/mentions_line.vue
index 09b6a1d6..161855e8 100644
--- a/src/components/mentions_line/mentions_line.vue
+++ b/src/components/mentions_line/mentions_line.vue
@@ -13,8 +13,7 @@
<span
v-if="expanded"
class="fullExtraMentions"
- >
- <MentionLink
+ >{{ ' ' }}<MentionLink
v-for="mention in extraMentions"
:key="mention.index"
class="mention-link"
diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue
index d2d48a03..c58d9e7c 100644
--- a/src/components/mobile_nav/mobile_nav.vue
+++ b/src/components/mobile_nav/mobile_nav.vue
@@ -86,6 +86,8 @@
@import '../../_variables.scss';
.MobileNav {
+ z-index: var(--ZI_navbar);
+
.mobile-nav {
display: grid;
line-height: var(--navbar-height);
@@ -147,7 +149,7 @@
transition-property: transform;
transition-duration: 0.25s;
transform: translateX(0);
- z-index: 1001;
+ z-index: var(--ZI_navbar);
-webkit-overflow-scrolling: touch;
&.-closed {
@@ -160,7 +162,7 @@
display: flex;
align-items: center;
justify-content: space-between;
- z-index: 1;
+ z-index: calc(var(--ZI_navbar) + 100);
width: 100%;
height: 50px;
line-height: 50px;
diff --git a/src/components/modal/modal.vue b/src/components/modal/modal.vue
index 9394efff..52d8d27e 100644
--- a/src/components/modal/modal.vue
+++ b/src/components/modal/modal.vue
@@ -22,6 +22,9 @@ export default {
default: false
}
},
+ provide: {
+ popoversZLayer: 'modals'
+ },
computed: {
classes () {
return {
@@ -35,7 +38,7 @@ export default {
<style lang="scss">
.modal-view {
- z-index: 2000;
+ z-index: var(--ZI_modals);
position: fixed;
top: 0;
left: 0;
diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue
index 7ae7b1d6..62aab7f1 100644
--- a/src/components/nav_panel/nav_panel.vue
+++ b/src/components/nav_panel/nav_panel.vue
@@ -113,7 +113,9 @@
border-color: $fallback--border;
border-color: var(--border, $fallback--border);
padding: 0;
+ }
+ > li {
&:first-child .menu-item {
border-top-right-radius: $fallback--panelRadius;
border-top-right-radius: var(--panelRadius, $fallback--panelRadius);
diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js
index 398bb7a9..77cdfa73 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 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'
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
@@ -46,7 +47,8 @@ const Notification = {
UserCard,
Timeago,
Status,
- RichContent
+ RichContent,
+ UserPopover
},
methods: {
toggleUserExpanded () {
diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue
index 7d3d0c69..6427d117 100644
--- a/src/components/notification/notification.vue
+++ b/src/components/notification/notification.vue
@@ -34,21 +34,22 @@
<a
class="avatar-container"
:href="$router.resolve(userProfileLink).href"
- @click.stop.prevent.capture="toggleUserExpanded"
+ @click.prevent
>
- <UserAvatar
- :compact="true"
- :better-shadow="betterShadow"
- :user="notification.from_profile"
- />
+ <UserPopover
+ :userId="notification.from_profile.id"
+ :overlayCenters="true"
+ >
+ <UserAvatar
+ class="post-avatar"
+ :bot="botIndicator"
+ :compact="true"
+ :better-shadow="betterShadow"
+ :user="notification.from_profile"
+ />
+ </UserPopover>
</a>
<div class="notification-right">
- <UserCard
- v-if="userExpanded"
- :user-id="getUser(notification).id"
- :rounded="true"
- :bordered="true"
- />
<span class="notification-details">
<div class="name-and-action">
<!-- eslint-disable vue/no-v-html -->
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
index 82aa1489..0851f407 100644
--- a/src/components/notifications/notifications.js
+++ b/src/components/notifications/notifications.js
@@ -1,3 +1,4 @@
+import { computed } from 'vue'
import { mapGetters } from 'vuex'
import Notification from '../notification/notification.vue'
import NotificationFilters from './notification_filters.vue'
@@ -40,6 +41,11 @@ const Notifications = {
seenToDisplayCount: DEFAULT_SEEN_TO_DISPLAY_COUNT
}
},
+ provide () {
+ return {
+ popoversZLayer: computed(() => this.popoversZLayer)
+ }
+ },
computed: {
mainClass () {
return this.minimalMode ? '' : 'panel panel-default'
@@ -77,6 +83,10 @@ const Notifications = {
}
return map[layoutType] || '#notifs-sidebar'
},
+ popoversZLayer () {
+ const { layoutType } = this.$store.state.interface
+ return layoutType === 'mobile' ? 'navbar' : null
+ },
notificationsToDisplay () {
return this.filteredNotifications.slice(0, this.unseenCount + this.seenToDisplayCount)
},
diff --git a/src/components/popover/popover.js b/src/components/popover/popover.js
index a30a37c9..58f7126d 100644
--- a/src/components/popover/popover.js
+++ b/src/components/popover/popover.js
@@ -31,13 +31,35 @@ const Popover = {
// If true, subtract padding when calculating position for the popover,
// use it when popover offset looks to be different on top vs bottom.
- removePadding: Boolean
+ removePadding: Boolean,
+
+ // self-explanatory (i hope)
+ disabled: Boolean,
+
+ // Instead of putting popover next to anchor, overlay popover's center on top of anchor's center
+ overlayCenters: Boolean,
+
+ // What selector (witin popover!) to use for determining center of popover
+ overlayCentersSelector: String,
+
+ // Lets hover popover stay when clicking inside of it
+ stayOnClick: Boolean
},
+ inject: ['popoversZLayer'], // override popover z layer
data () {
return {
+ // lockReEntry is a flag that is set when mouse cursor is leaving the popover's content
+ // so that if mouse goes back into popover it won't be re-shown again to prevent annoyance
+ // with popovers refusing to be hidden when user wants to interact with something in below popover
+ lockReEntry: false,
hidden: true,
- styles: { opacity: 0 },
- oldSize: { width: 0, height: 0 }
+ styles: {},
+ oldSize: { width: 0, height: 0 },
+ scrollable: null,
+ // used to avoid blinking if hovered onto popover
+ graceTimeout: null,
+ parentPopover: null,
+ childrenShown: new Set()
}
},
methods: {
@@ -47,9 +69,7 @@ const Popover = {
},
updateStyles () {
if (this.hidden) {
- this.styles = {
- opacity: 0
- }
+ this.styles = {}
return
}
@@ -57,14 +77,26 @@ const Popover = {
// its children are what are inside the slot. Expect only one v-slot:trigger.
const anchorEl = (this.$refs.trigger && this.$refs.trigger.children[0]) || this.$el
// SVGs don't have offsetWidth/Height, use fallback
- const anchorWidth = anchorEl.offsetWidth || anchorEl.clientWidth
const anchorHeight = anchorEl.offsetHeight || anchorEl.clientHeight
- const screenBox = anchorEl.getBoundingClientRect()
- // Screen position of the origin point for popover
- const origin = { x: screenBox.left + screenBox.width * 0.5, y: screenBox.top }
+ const anchorWidth = anchorEl.offsetWidth || anchorEl.clientWidth
+ const anchorScreenBox = anchorEl.getBoundingClientRect()
+
+ const anchorStyle = getComputedStyle(anchorEl)
+ const topPadding = parseFloat(anchorStyle.paddingTop)
+ const bottomPadding = parseFloat(anchorStyle.paddingBottom)
+
+ // Screen position of the origin point for popover = center of the anchor
+ const origin = {
+ x: anchorScreenBox.left + anchorWidth * 0.5,
+ y: anchorScreenBox.top + anchorHeight * 0.5
+ }
const content = this.$refs.content
+ const overlayCenter = this.overlayCenters
+ ? this.$refs.content.querySelector(this.overlayCentersSelector)
+ : null
+
// Minor optimization, don't call a slow reflow call if we don't have to
- const parentBounds = this.boundTo &&
+ const parentScreenBox = this.boundTo &&
(this.boundTo.x === 'container' || this.boundTo.y === 'container') &&
this.containerBoundingClientRect()
@@ -73,81 +105,151 @@ const Popover = {
// What are the screen bounds for the popover? Viewport vs container
// when using viewport, using default margin values to dodge the navbar
const xBounds = this.boundTo && this.boundTo.x === 'container' ? {
- min: parentBounds.left + (margin.left || 0),
- max: parentBounds.right - (margin.right || 0)
+ min: parentScreenBox.left + (margin.left || 0),
+ max: parentScreenBox.right - (margin.right || 0)
} : {
min: 0 + (margin.left || 10),
max: window.innerWidth - (margin.right || 10)
}
const yBounds = this.boundTo && this.boundTo.y === 'container' ? {
- min: parentBounds.top + (margin.top || 0),
- max: parentBounds.bottom - (margin.bottom || 0)
+ min: parentScreenBox.top + (margin.top || 0),
+ max: parentScreenBox.bottom - (margin.bottom || 0)
} : {
min: 0 + (margin.top || 50),
max: window.innerHeight - (margin.bottom || 5)
}
let horizOffset = 0
+ let vertOffset = 0
+
+ if (overlayCenter) {
+ const box = content.getBoundingClientRect()
+ const overlayCenterScreenBox = overlayCenter.getBoundingClientRect()
+ const leftInnerOffset = overlayCenterScreenBox.left - box.left
+ const topInnerOffset = overlayCenterScreenBox.top - box.top
+ horizOffset = -leftInnerOffset - overlayCenter.offsetWidth * 0.5
+ vertOffset = -topInnerOffset - overlayCenter.offsetHeight * 0.5
+ } else {
+ horizOffset = content.offsetWidth * -0.5
+ vertOffset = content.offsetHeight * -0.5
+ }
+
+ const leftBorder = origin.x + horizOffset
+ const rightBorder = leftBorder + content.offsetWidth
+ const topBorder = origin.y + vertOffset
+ const bottomBorder = topBorder + content.offsetHeight
// If overflowing from left, move it so that it doesn't
- if ((origin.x - content.offsetWidth * 0.5) < xBounds.min) {
- horizOffset += -(origin.x - content.offsetWidth * 0.5) + xBounds.min
+ if (leftBorder < xBounds.min) {
+ horizOffset += xBounds.min - leftBorder
}
// If overflowing from right, move it so that it doesn't
- if ((origin.x + horizOffset + content.offsetWidth * 0.5) > xBounds.max) {
- horizOffset -= (origin.x + horizOffset + content.offsetWidth * 0.5) - xBounds.max
+ if (rightBorder > xBounds.max) {
+ horizOffset -= rightBorder - xBounds.max
}
- // Default to whatever user wished with placement prop
- let usingTop = this.placement !== 'bottom'
-
- // Handle special cases, first force to displaying on top if there's not space on bottom,
- // regardless of what placement value was. Then check if there's not space on top, and
- // force to bottom, again regardless of what placement value was.
- if (origin.y + content.offsetHeight > yBounds.max) usingTop = true
- if (origin.y - content.offsetHeight < yBounds.min) usingTop = false
+ // If overflowing from top, move it so that it doesn't
+ if (topBorder < yBounds.min) {
+ vertOffset += yBounds.min - topBorder
+ }
- let vPadding = 0
- if (this.removePadding && usingTop) {
- const anchorStyle = getComputedStyle(anchorEl)
- vPadding = parseFloat(anchorStyle.paddingTop) + parseFloat(anchorStyle.paddingBottom)
+ // If overflowing from bottom, move it so that it doesn't
+ if (bottomBorder > yBounds.max) {
+ vertOffset -= bottomBorder - yBounds.max
}
- const yOffset = (this.offset && this.offset.y) || 0
- const translateY = usingTop
- ? -anchorHeight + vPadding - yOffset - content.offsetHeight
- : yOffset
+ let translateX = 0
+ let translateY = 0
+
+ if (overlayCenter) {
+ translateX = origin.x + horizOffset
+ translateY = origin.y + vertOffset
+ } else {
+ // Default to whatever user wished with placement prop
+ let usingTop = this.placement !== 'bottom'
+
+ // Handle special cases, first force to displaying on top if there's not space on bottom,
+ // regardless of what placement value was. Then check if there's not space on top, and
+ // force to bottom, again regardless of what placement value was.
+ const topBoundary = origin.y - anchorHeight * 0.5 + (this.removePadding ? topPadding : 0)
+ const bottomBoundary = origin.y + anchorHeight * 0.5 - (this.removePadding ? bottomPadding : 0)
+ if (bottomBoundary + content.offsetHeight > yBounds.max) usingTop = true
+ if (topBoundary - content.offsetHeight < yBounds.min) usingTop = false
- const xOffset = (this.offset && this.offset.x) || 0
- const translateX = anchorWidth * 0.5 - content.offsetWidth * 0.5 + horizOffset + xOffset
+ const yOffset = (this.offset && this.offset.y) || 0
+ translateY = usingTop
+ ? topBoundary - yOffset - content.offsetHeight
+ : bottomBoundary + yOffset
+
+ const xOffset = (this.offset && this.offset.x) || 0
+ translateX = origin.x + horizOffset + xOffset
+ }
- // Note, separate translateX and translateY avoids blurry text on chromium,
- // single translate or translate3d resulted in blurry text.
this.styles = {
- opacity: 1,
- transform: `translateX(${Math.round(translateX)}px) translateY(${Math.round(translateY)}px)`
+ left: `${Math.round(translateX)}px`,
+ top: `${Math.round(translateY)}px`
+ }
+
+ if (this.popoversZLayer) {
+ this.styles['--ZI_popover_override'] = `var(--ZI_${this.popoversZLayer}_popovers)`
+ }
+ if (parentScreenBox) {
+ this.styles.maxWidth = `${Math.round(parentScreenBox.width)}px`
}
},
showPopover () {
+ if (this.disabled) return
const wasHidden = this.hidden
this.hidden = false
+ this.parentPopover && this.parentPopover.onChildPopoverState(this, true)
+ if (this.trigger === 'click' || this.stayOnClick) {
+ document.addEventListener('click', this.onClickOutside)
+ }
+ this.scrollable.addEventListener('scroll', this.onScroll)
+ this.scrollable.addEventListener('resize', this.onResize)
this.$nextTick(() => {
if (wasHidden) this.$emit('show')
this.updateStyles()
})
},
hidePopover () {
+ if (this.disabled) return
if (!this.hidden) this.$emit('close')
this.hidden = true
- this.styles = { opacity: 0 }
+ this.parentPopover && this.parentPopover.onChildPopoverState(this, false)
+ if (this.trigger === 'click') {
+ document.removeEventListener('click', this.onClickOutside)
+ }
+ this.scrollable.removeEventListener('scroll', this.onScroll)
+ this.scrollable.removeEventListener('resize', this.onResize)
},
onMouseenter (e) {
- if (this.trigger === 'hover') this.showPopover()
+ if (this.trigger === 'hover') {
+ this.lockReEntry = false
+ clearTimeout(this.graceTimeout)
+ this.graceTimeout = null
+ this.showPopover()
+ }
},
onMouseleave (e) {
- if (this.trigger === 'hover') this.hidePopover()
+ if (this.trigger === 'hover' && this.childrenShown.size === 0) {
+ this.graceTimeout = setTimeout(() => this.hidePopover(), 1)
+ }
+ },
+ onMouseenterContent (e) {
+ if (this.trigger === 'hover' && !this.lockReEntry) {
+ this.lockReEntry = true
+ clearTimeout(this.graceTimeout)
+ this.graceTimeout = null
+ this.showPopover()
+ }
+ },
+ onMouseleaveContent (e) {
+ if (this.trigger === 'hover' && this.childrenShown.size === 0) {
+ this.graceTimeout = setTimeout(() => this.hidePopover(), 1)
+ }
},
onClick (e) {
if (this.trigger === 'click') {
@@ -160,8 +262,24 @@ const Popover = {
},
onClickOutside (e) {
if (this.hidden) return
+ if (this.$refs.content && this.$refs.content.contains(e.target)) return
if (this.$el.contains(e.target)) return
+ if (this.childrenShown.size > 0) return
this.hidePopover()
+ if (this.parentPopover) this.parentPopover.onClickOutside(e)
+ },
+ onScroll (e) {
+ this.updateStyles()
+ },
+ onResize (e) {
+ this.updateStyles()
+ },
+ onChildPopoverState (childRef, state) {
+ if (state) {
+ this.childrenShown.add(childRef)
+ } else {
+ this.childrenShown.delete(childRef)
+ }
}
},
updated () {
@@ -175,11 +293,18 @@ const Popover = {
this.oldSize = { width: content.offsetWidth, height: content.offsetHeight }
}
},
- created () {
- document.addEventListener('click', this.onClickOutside)
+ mounted () {
+ let scrollable = this.$refs.trigger.closest('.column.-scrollable') ||
+ this.$refs.trigger.closest('.mobile-notifications')
+ if (!scrollable) scrollable = window
+ this.scrollable = scrollable
+ let parent = this.$parent
+ while (parent && parent.$.type.name !== 'Popover') {
+ parent = parent.$parent
+ }
+ this.parentPopover = parent
},
- unmounted () {
- document.removeEventListener('click', this.onClickOutside)
+ beforeUnmount () {
this.hidePopover()
}
}
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index c2a3e801..bd59cade 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -1,5 +1,5 @@
<template>
- <div
+ <span
@mouseenter="onMouseenter"
@mouseleave="onMouseleave"
>
@@ -11,20 +11,27 @@
>
<slot name="trigger" />
</button>
- <div
- v-if="!hidden"
- ref="content"
- :style="styles"
- class="popover"
- :class="popoverClass || 'popover-default'"
- >
- <slot
- name="content"
- class="popover-inner"
- :close="hidePopover"
- />
- </div>
- </div>
+ <teleport to="#popovers">
+ <transition name="fade">
+ <div
+ v-if="!hidden"
+ ref="content"
+ :style="styles"
+ class="popover"
+ :class="popoverClass || 'popover-default'"
+ @mouseenter="onMouseenterContent"
+ @mouseleave="onMouseleaveContent"
+ @click="onClickContent"
+ >
+ <slot
+ name="content"
+ class="popover-inner"
+ :close="hidePopover"
+ />
+ </div>
+ </transition>
+ </teleport>
+ </span>
</template>
<script src="./popover.js" />
@@ -37,14 +44,15 @@
}
.popover {
- z-index: 500;
- position: absolute;
+ z-index: var(--ZI_popover_override, var(--ZI_popovers));
+ position: fixed;
min-width: 0;
+ max-width: calc(100vw - 20px);
+ box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5);
+ box-shadow: var(--popupShadow);
}
.popover-default {
- transition: opacity 0.3s;
-
&:after {
content: '';
position: absolute;
@@ -80,7 +88,7 @@
text-align: left;
list-style: none;
max-width: 100vw;
- z-index: 200;
+ z-index: var(--ZI_popover_override, var(--ZI_popovers));
white-space: nowrap;
.dropdown-divider {
diff --git a/src/components/react_button/react_button.vue b/src/components/react_button/react_button.vue
index 8a4b4d3b..b76fb244 100644
--- a/src/components/react_button/react_button.vue
+++ b/src/components/react_button/react_button.vue
@@ -6,6 +6,7 @@
:offset="{ y: 5 }"
:bound-to="{ x: 'container' }"
remove-padding
+ popover-class="ReactButton popover-default"
@show="focusInput"
>
<template v-slot:content="{close}">
@@ -41,7 +42,7 @@
</div>
</template>
<template v-slot:trigger>
- <button
+ <span
class="button-unstyled popover-trigger"
:title="$t('tool_tip.add_reaction')"
>
@@ -49,7 +50,7 @@
class="fa-scale-110 fa-old-padding"
:icon="['far', 'smile-beam']"
/>
- </button>
+ </span>
</template>
</Popover>
</template>
diff --git a/src/components/settings_modal/helpers/modified_indicator.vue b/src/components/settings_modal/helpers/modified_indicator.vue
index ad212db9..74366dc1 100644
--- a/src/components/settings_modal/helpers/modified_indicator.vue
+++ b/src/components/settings_modal/helpers/modified_indicator.vue
@@ -41,11 +41,11 @@ export default {
.ModifiedIndicator {
display: inline-block;
position: relative;
+}
- .modified-tooltip {
- margin: 0.5em 1em;
- min-width: 10em;
- text-align: center;
- }
+.modified-tooltip {
+ margin: 0.5em 1em;
+ min-width: 10em;
+ text-align: center;
}
</style>
diff --git a/src/components/settings_modal/helpers/server_side_indicator.vue b/src/components/settings_modal/helpers/server_side_indicator.vue
index 143a86a1..cf53eb6a 100644
--- a/src/components/settings_modal/helpers/server_side_indicator.vue
+++ b/src/components/settings_modal/helpers/server_side_indicator.vue
@@ -41,11 +41,11 @@ export default {
.ServerSideIndicator {
display: inline-block;
position: relative;
+}
- .serverside-tooltip {
- margin: 0.5em 1em;
- min-width: 10em;
- text-align: center;
- }
+.serverside-tooltip {
+ margin: 0.5em 1em;
+ min-width: 10em;
+ text-align: center;
}
</style>
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index 1fe51b6d..e201ab9d 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -75,6 +75,16 @@
</BooleanSetting>
</li>
<li>
+ <BooleanSetting path="userPopoverZoom" expert="1">
+ {{ $t('settings.user_popover_avatar_zoom') }}
+ </BooleanSetting>
+ </li>
+ <li>
+ <BooleanSetting path="userPopoverOverlay" expert="1">
+ {{ $t('settings.user_popover_avatar_overlay') }}
+ </BooleanSetting>
+ </li>
+ <li>
<ChoiceSetting
v-if="user"
id="thirdColumnMode"
@@ -261,18 +271,14 @@
{{ $t('settings.mention_link_display') }}
</ChoiceSetting>
</li>
- <ul
- class="setting-list suboptions"
- >
- <li v-if="mentionLinkDisplay === 'short'">
- <BooleanSetting
- path="mentionLinkShowTooltip"
- expert="1"
- >
- {{ $t('settings.mention_link_show_tooltip') }}
- </BooleanSetting>
- </li>
- </ul>
+ <li>
+ <BooleanSetting
+ path="mentionLinkShowTooltip"
+ expert="1"
+ >
+ {{ $t('settings.mention_link_use_tooltip') }}
+ </BooleanSetting>
+ </li>
<li>
<BooleanSetting
path="useAtIcon"
diff --git a/src/components/shout_panel/shout_panel.vue b/src/components/shout_panel/shout_panel.vue
index 1eca88a7..688c2d61 100644
--- a/src/components/shout_panel/shout_panel.vue
+++ b/src/components/shout_panel/shout_panel.vue
@@ -80,7 +80,7 @@
.floating-shout {
position: fixed;
bottom: 0.5em;
- z-index: 1000;
+ z-index: var(--ZI_popovers);
max-width: 25em;
&.-left {
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index dd88de7d..aefd3915 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -211,7 +211,7 @@
.side-drawer-container {
position: fixed;
- z-index: 1000;
+ z-index: var(--ZI_navbar);
top: 0;
left: 0;
width: 100%;
diff --git a/src/components/status/status.js b/src/components/status/status.js
index a925f30b..053c9441 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -4,13 +4,13 @@ import ReactButton from '../react_button/react_button.vue'
import RetweetButton from '../retweet_button/retweet_button.vue'
import ExtraButtons from '../extra_buttons/extra_buttons.vue'
import PostStatusForm from '../post_status_form/post_status_form.vue'
-import UserCard from '../user_card/user_card.vue'
import UserAvatar from '../user_avatar/user_avatar.vue'
import AvatarList from '../avatar_list/avatar_list.vue'
import Timeago from '../timeago/timeago.vue'
import StatusContent from '../status_content/status_content.vue'
import RichContent from 'src/components/rich_content/rich_content.jsx'
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 MentionsLine from 'src/components/mentions_line/mentions_line.vue'
@@ -105,7 +105,6 @@ const Status = {
RetweetButton,
ExtraButtons,
PostStatusForm,
- UserCard,
UserAvatar,
AvatarList,
Timeago,
@@ -115,7 +114,8 @@ const Status = {
StatusContent,
RichContent,
MentionLink,
- MentionsLine
+ MentionsLine,
+ UserPopover
},
props: [
'statusoid',
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 67ce999a..bbb41d41 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -122,27 +122,22 @@
v-if="!noHeading"
class="left-side"
>
- <a
- :href="$router.resolve(userProfileLink).href"
- @click.stop.prevent.capture="toggleUserExpanded"
- >
- <UserAvatar
- class="post-avatar"
- :bot="botIndicator"
- :compact="compact"
- :better-shadow="betterShadow"
- :user="status.user"
- />
+ <a :href="$router.resolve(userProfileLink).href" @click.prevent>
+ <UserPopover
+ :userId="status.user.id"
+ :overlayCenters="true"
+ >
+ <UserAvatar
+ class="post-avatar"
+ :bot="botIndicator"
+ :compact="compact"
+ :better-shadow="betterShadow"
+ :user="status.user"
+ />
+ </UserPopover>
</a>
</div>
<div class="right-side">
- <UserCard
- v-if="userExpanded"
- :user-id="status.user.id"
- :rounded="true"
- :bordered="true"
- class="usercard"
- />
<div
v-if="!noHeading"
class="status-heading"
@@ -322,6 +317,7 @@
class="mentions-line-first"
/>
</span>
+ {{ ' ' }}
<MentionsLine
v-if="hasMentionsLine"
:mentions="mentionsLine.slice(1)"
diff --git a/src/components/status_popover/status_popover.js b/src/components/status_popover/status_popover.js
index e0962ccd..c55bd85b 100644
--- a/src/components/status_popover/status_popover.js
+++ b/src/components/status_popover/status_popover.js
@@ -38,6 +38,13 @@ const StatusPopover = {
.catch(e => (this.error = true))
}
}
+ },
+ watch: {
+ status (newStatus, oldStatus) {
+ if (newStatus !== oldStatus) {
+ this.$nextTick(() => this.$refs.popover.updateStyles())
+ }
+ }
}
}
diff --git a/src/components/status_popover/status_popover.vue b/src/components/status_popover/status_popover.vue
index fdca8c9c..9cabb751 100644
--- a/src/components/status_popover/status_popover.vue
+++ b/src/components/status_popover/status_popover.vue
@@ -1,9 +1,11 @@
<template>
<Popover
trigger="hover"
+ :stay-on-click="true"
popover-class="popover-default status-popover"
:bound-to="{ x: 'container' }"
@show="enter"
+ ref="popover"
>
<template v-slot:trigger>
<slot />
@@ -52,8 +54,6 @@
border-width: 1px;
border-radius: $fallback--tooltipRadius;
border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
- box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5);
- box-shadow: var(--popupShadow);
/* TODO cleanup this */
.Status.Status {
diff --git a/src/components/timeline_menu/timeline_menu.vue b/src/components/timeline_menu/timeline_menu.vue
index 61119482..1e054f5a 100644
--- a/src/components/timeline_menu/timeline_menu.vue
+++ b/src/components/timeline_menu/timeline_menu.vue
@@ -3,19 +3,17 @@
trigger="click"
class="TimelineMenu"
:class="{ 'open': isOpen }"
- :margin="{ left: -15, right: -200 }"
:bound-to="{ x: 'container' }"
- popover-class="timeline-menu-popover-wrap"
+ bound-to-selector=".Timeline"
+ popover-class="timeline-menu-popover popover-default"
@show="openMenu"
@close="() => isOpen = false"
>
<template v-slot:content>
- <div class="timeline-menu-popover popover-default">
- <TimelineMenuContent />
- </div>
+ <TimelineMenuContent />
</template>
<template v-slot:trigger>
- <button class="button-unstyled title timeline-menu-title">
+ <span class="button-unstyled title timeline-menu-title">
<span class="timeline-title">{{ timelineName() }}</span>
<span>
<FAIcon
@@ -27,7 +25,7 @@
class="click-blocker"
@click="blockOpen"
/>
- </button>
+ </span>
</template>
</Popover>
</template>
@@ -38,42 +36,18 @@
@import '../../_variables.scss';
.TimelineMenu {
- flex-shrink: 1;
margin-right: auto;
min-width: 0;
- width: 24rem;
.popover-trigger-button {
vertical-align: bottom;
}
- .timeline-menu-popover-wrap {
- overflow: hidden;
- // Match panel heading padding to line up menu with bottom of heading
- margin-top: 0.6rem;
- padding: 0 15px 15px 15px;
- }
-
- .timeline-menu-popover {
- width: 24rem;
- max-width: 100vw;
- margin: 0;
- font-size: 1rem;
- border-top-right-radius: 0;
- border-top-left-radius: 0;
- transform: translateY(-100%);
- transition: transform 100ms;
- }
-
.panel::after {
border-top-right-radius: 0;
border-top-left-radius: 0;
}
- &.open .timeline-menu-popover {
- transform: translateY(0);
- }
-
.timeline-menu-title {
margin: 0;
cursor: pointer;
@@ -108,6 +82,16 @@
box-shadow: var(--popoverShadow);
}
+}
+
+.timeline-menu-popover {
+ min-width: 24rem;
+ max-width: 100vw;
+ margin-top: 0.6rem;
+ font-size: 1rem;
+ border-top-right-radius: 0;
+ border-top-left-radius: 0;
+
ul {
list-style: none;
margin: 0;
@@ -134,7 +118,9 @@
a {
display: block;
- padding: 0.6em 0.65em;
+ padding: 0 0.65em;
+ height: 3.5em;
+ line-height: 3.5em;
&:hover {
background-color: $fallback--lightBg;
diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js
index 4168c54a..b0fa11b3 100644
--- a/src/components/user_card/user_card.js
+++ b/src/components/user_card/user_card.js
@@ -14,7 +14,9 @@ import {
faRss,
faSearchPlus,
faExternalLinkAlt,
- faEdit
+ faEdit,
+ faTimes,
+ faExpandAlt
} from '@fortawesome/free-solid-svg-icons'
library.add(
@@ -22,12 +24,21 @@ library.add(
faBell,
faSearchPlus,
faExternalLinkAlt,
- faEdit
+ faEdit,
+ faTimes,
+ faExpandAlt
)
export default {
props: [
- 'userId', 'switcher', 'selected', 'hideBio', 'rounded', 'bordered', 'allowZoomingAvatar'
+ 'userId',
+ 'switcher',
+ 'selected',
+ 'hideBio',
+ 'rounded',
+ 'bordered',
+ 'avatarAction', // default - open profile, 'zoom' - zoom, function - call function
+ 'onClose'
],
data () {
return {
@@ -47,9 +58,10 @@ export default {
},
classes () {
return [{
- 'user-card-rounded-t': this.rounded === 'top', // set border-top-left-radius and border-top-right-radius
- 'user-card-rounded': this.rounded === true, // set border-radius for all sides
- 'user-card-bordered': this.bordered === true // set border for all sides
+ '-rounded-t': this.rounded === 'top', // set border-top-left-radius and border-top-right-radius
+ '-rounded': this.rounded === true, // set border-radius for all sides
+ '-bordered': this.bordered === true, // set border for all sides
+ '-popover': !!this.onClose // set popover rounding
}]
},
style () {
@@ -170,6 +182,12 @@ export default {
},
mentionUser () {
this.$store.dispatch('openPostStatusModal', { replyTo: true, repliedUser: this.user })
+ },
+ onAvatarClickHandler (e) {
+ if (this.onAvatarClick) {
+ e.preventDefault()
+ this.onAvatarClick()
+ }
}
}
}
diff --git a/src/components/user_card/user_card.scss b/src/components/user_card/user_card.scss
index 2e153120..a0bbc6a6 100644
--- a/src/components/user_card/user_card.scss
+++ b/src/components/user_card/user_card.scss
@@ -42,8 +42,10 @@
mask-composite: exclude;
background-size: cover;
mask-size: 100% 60%;
- border-top-left-radius: calc(var(--panelRadius) - 1px);
- border-top-right-radius: calc(var(--panelRadius) - 1px);
+ border-top-left-radius: calc(var(--__roundnessTop, --panelRadius) - 1px);
+ border-top-right-radius: calc(var(--__roundnessTop, --panelRadius) - 1px);
+ border-bottom-left-radius: calc(var(--__roundnessBottom, --panelRadius) - 1px);
+ border-bottom-right-radius: calc(var(--__roundnessBottom, --panelRadius) - 1px);
background-color: var(--profileBg);
z-index: -2;
@@ -72,21 +74,33 @@
}
}
- // Modifiers
-
- &-rounded-t {
+ &.-rounded-t {
border-top-left-radius: $fallback--panelRadius;
border-top-left-radius: var(--panelRadius, $fallback--panelRadius);
border-top-right-radius: $fallback--panelRadius;
border-top-right-radius: var(--panelRadius, $fallback--panelRadius);
+
+ --__roundnessTop: var(--panelRadius);
+ --__roundnessBottom: 0;
}
- &-rounded {
+ &.-rounded {
border-radius: $fallback--panelRadius;
border-radius: var(--panelRadius, $fallback--panelRadius);
+
+ --__roundnessTop: var(--panelRadius);
+ --__roundnessBottom: var(--panelRadius);
}
- &-bordered {
+ &.-popover {
+ border-radius: $fallback--tooltipRadius;
+ border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
+
+ --__roundnessTop: var(--tooltipRadius);
+ --__roundnessBottom: var(--tooltipRadius);
+ }
+
+ &.-bordered {
border-width: 1px;
border-style: solid;
border-color: $fallback--border;
@@ -99,6 +113,15 @@
color: var(--lightText, $fallback--lightText);
padding: 0 26px;
+ a {
+ color: $fallback--lightText;
+ color: var(--lightText, $fallback--lightText);
+
+ &:hover {
+ color: var(--icon);
+ }
+ }
+
.container {
min-width: 0;
padding: 16px 0 6px;
@@ -110,23 +133,27 @@
min-width: 0;
}
+ > a {
+ vertical-align: middle;
+ display: flex;
+ }
+
.Avatar {
--_avatarShadowBox: var(--avatarShadow);
--_avatarShadowFilter: var(--avatarShadowFilter);
--_avatarShadowInset: var(--avatarShadowInset);
- flex: 1 0 100%;
width: 56px;
height: 56px;
object-fit: cover;
}
}
- &-avatar-link {
+ &-avatar {
position: relative;
cursor: pointer;
- &-overlay {
+ &.-overlay {
position: absolute;
left: 0;
top: 0;
@@ -146,7 +173,7 @@
}
}
- &:hover &-overlay {
+ &:hover &.-overlay {
opacity: 1;
}
}
@@ -206,8 +233,6 @@
flex: 0 1 auto;
text-overflow: ellipsis;
overflow: hidden;
- color: $fallback--lightText;
- color: var(--lightText, $fallback--lightText);
}
.dailyAvg {
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index 67837845..bc23e68e 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -8,25 +8,32 @@
:style="style"
class="background-image"
/>
- <div class="panel-heading -flexible-height">
+ <div :class="onClose ? '' : panel-heading -flexible-height">
<div class="user-info">
<div class="container">
<a
- v-if="allowZoomingAvatar"
- class="user-info-avatar-link"
+ v-if="avatarAction === 'zoom'"
+ class="user-info-avatar -link"
@click="zoomAvatar"
>
<UserAvatar
:better-shadow="betterShadow"
:user="user"
/>
- <div class="user-info-avatar-link-overlay">
+ <div class="user-info-avatar -link -overlay">
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="search-plus"
/>
</div>
</a>
+ <UserAvatar
+ v-else-if="typeof avatarAction === 'function'"
+ @click="avatarAction"
+ class="user-info-avatar"
+ :better-shadow="betterShadow"
+ :user="user"
+ />
<router-link
v-else
:to="userProfileLink(user)"
@@ -38,12 +45,16 @@
</router-link>
<div class="user-summary">
<div class="top-line">
- <RichContent
- :title="user.name"
+ <router-link
+ :to="userProfileLink(user)"
class="user-name"
- :html="user.name"
- :emoji="user.emoji"
- />
+ >
+ <RichContent
+ :title="user.name"
+ :html="user.name"
+ :emoji="user.emoji"
+ />
+ </router-link>
<button
v-if="!isOtherUser && user.is_local"
class="button-unstyled edit-profile-button"
@@ -72,6 +83,27 @@
:user="user"
:relationship="relationship"
/>
+ <router-link
+ v-if="onClose"
+ :to="userProfileLink(user)"
+ class="button-unstyled external-link-button"
+ @click="onClose"
+ >
+ <FAIcon
+ class="icon"
+ icon="expand-alt"
+ />
+ </router-link>
+ <button
+ v-if="onClose"
+ class="button-unstyled external-link-button"
+ @click="onClose"
+ >
+ <FAIcon
+ class="icon"
+ icon="times"
+ />
+ </button>
</div>
<div class="bottom-line">
<router-link
diff --git a/src/components/user_popover/user_popover.js b/src/components/user_popover/user_popover.js
new file mode 100644
index 00000000..69b25383
--- /dev/null
+++ b/src/components/user_popover/user_popover.js
@@ -0,0 +1,23 @@
+import UserCard from '../user_card/user_card.vue'
+import { defineAsyncComponent } from 'vue'
+
+const UserPopover = {
+ name: 'UserPopover',
+ props: [
+ 'userId', 'overlayCenters', 'disabled', 'overlayCentersSelector'
+ ],
+ components: {
+ UserCard,
+ Popover: defineAsyncComponent(() => import('../popover/popover.vue'))
+ },
+ computed: {
+ userPopoverZoom () {
+ return this.$store.getters.mergedConfig.userPopoverZoom
+ },
+ userPopoverOverlay () {
+ return this.$store.getters.mergedConfig.userPopoverOverlay
+ }
+ }
+}
+
+export default UserPopover
diff --git a/src/components/user_popover/user_popover.vue b/src/components/user_popover/user_popover.vue
new file mode 100644
index 00000000..72bb7f77
--- /dev/null
+++ b/src/components/user_popover/user_popover.vue
@@ -0,0 +1,33 @@
+<template>
+<Popover
+ trigger="click"
+ popover-class="popover-default user-popover"
+ :overlay-centers-selector="overlayCentersSelector || '.user-info .Avatar'"
+ :overlay-centers="overlayCenters && userPopoverOverlay"
+ :disabled="disabled"
+>
+ <template v-slot:trigger>
+ <slot />
+ </template>
+ <template v-slot:content={close}>
+ <UserCard
+ class="user-popover"
+ :user-id="userId"
+ :hide-bio="true"
+ :avatar-action="userPopoverZoom ? 'zoom' : close"
+ :on-close="close"
+ />
+ </template>
+</Popover>
+</template>
+
+<script src="./user_popover.js" ></script>
+
+<style lang="scss">
+@import '../../_variables.scss';
+
+/* popover styles load on-demand, so we need to override */
+.user-popover.popover {
+}
+
+</style>
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index 62792599..dbf28981 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -8,7 +8,7 @@
:user-id="userId"
:switcher="true"
:selected="timeline.viewing"
- :allow-zooming-avatar="true"
+ avatar-action="zoom"
rounded="top"
/>
<div
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 8ad411b2..fe02664f 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -546,10 +546,12 @@
"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_use_tooltip": "Show user card when clicking mention links",
"mention_link_show_avatar": "Show user avatar beside the link",
"mention_link_fade_domain": "Fade domains (e.g. {'@'}example.org in {'@'}foo{'@'}example.org)",
"mention_link_bolden_you": "Highlight mention of you when you are mentioned",
+ "user_popover_avatar_zoom": "Clicking on user avatar in popover zooms it instead of closing the popover",
+ "user_popover_avatar_overlay": "Show user popover over user avatar",
"fun": "Fun",
"greentext": "Meme arrows",
"show_yous": "Show (You)s",
diff --git a/src/modules/config.js b/src/modules/config.js
index 6ae2e754..f7f142ad 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -81,6 +81,8 @@ export const defaultState = {
useContainFit: true,
disableStickyHeaders: false,
showScrollbars: false,
+ userPopoverZoom: false,
+ userPopoverOverlay: true,
greentext: undefined, // instance default
useAtIcon: undefined, // instance default
mentionLinkDisplay: undefined, // instance default
diff --git a/test/unit/specs/components/rich_content.spec.js b/test/unit/specs/components/rich_content.spec.js
index 958fb997..8a18a08b 100644
--- a/test/unit/specs/components/rich_content.spec.js
+++ b/test/unit/specs/components/rich_content.spec.js
@@ -4,7 +4,15 @@ import RichContent from 'src/components/rich_content/rich_content.jsx'
const attentions = []
const global = {
mocks: {
- '$store': null
+ '$store': {
+ state: {},
+ getters: {
+ mergedConfig: () => ({
+ mentionLinkShowTooltip: true
+ }),
+ findUserByUrl: () => null
+ }
+ }
},
stubs: {
FAIcon: true
@@ -131,8 +139,7 @@ describe('RichContent', () => {
].join(''),
[
makeMention('John'),
- makeMention('Josh'),
- makeMention('Jeremy')
+ makeMention('Josh'), makeMention('Jeremy')
].join('')
].join('\n')
@@ -349,7 +356,6 @@ describe('RichContent', () => {
p(
'<span class="MentionsLine">',
'<span class="MentionLink mention-link">',
- '<!-- eslint-disable vue/no-v-html -->',
'<a href="lol" class="original" target="_blank">',
'<span>',
'https://</span>',
@@ -358,10 +364,7 @@ describe('RichContent', () => {
'<span>',
'</span>',
'</a>',
- '<!-- eslint-enable vue/no-v-html -->',
- '<!--v-if-->', // v-if placeholder, mentionlink's "new" (i.e. rich) display
'</span>',
- '<!--v-if-->', // v-if placeholder, mentionsline's extra mentions and stuff
'</span>'
),
p(
@@ -380,7 +383,7 @@ describe('RichContent', () => {
}
})
- expect(wrapper.html().replace(/\n/g, '')).to.eql(compwrap(expected))
+ expect(wrapper.html().replace(/\n/g, '').replace(/<!--.*?-->/g, '')).to.eql(compwrap(expected))
})
it('rich contents of nested mentions are handled properly', () => {
@@ -412,7 +415,6 @@ describe('RichContent', () => {
'<span class="poast-style">',
'<span class="MentionsLine">',
'<span class="MentionLink mention-link">',
- '<!-- eslint-disable vue/no-v-html -->',
'<a href="lol" class="original" target="_blank">',
'<span>',
'https://</span>',
@@ -421,11 +423,8 @@ describe('RichContent', () => {
'<span>',
'</span>',
'</a>',
- '<!-- eslint-enable vue/no-v-html -->',
- '<!--v-if-->', // v-if placeholder, mentionlink's "new" (i.e. rich) display
'</span>',
'<span class="MentionLink mention-link">',
- '<!-- eslint-disable vue/no-v-html -->',
'<a href="lol" class="original" target="_blank">',
'<span>',
'https://</span>',
@@ -434,10 +433,7 @@ describe('RichContent', () => {
'<span>',
'</span>',
'</a>',
- '<!-- eslint-enable vue/no-v-html -->',
- '<!--v-if-->', // v-if placeholder, mentionlink's "new" (i.e. rich) display
'</span>',
- '<!--v-if-->', // v-if placeholder, mentionsline's extra mentions and stuff
'</span>',
' ',
'</span>',
@@ -455,7 +451,7 @@ describe('RichContent', () => {
}
})
- expect(wrapper.html().replace(/\n/g, '')).to.eql(compwrap(expected))
+ expect(wrapper.html().replace(/\n/g, '').replace(/<!--.*?-->/g, '')).to.eql(compwrap(expected))
})
it('rich contents of a link are handled properly', () => {