logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe
commit: 111c1ced676da55b5ccd8f119e5f069f53e04958
parent: d19c64314ff08391a2649681e6b64d052e600059
Author: Shpuld Shpludson <shp@cock.li>
Date:   Fri, 28 Feb 2020 16:39:47 +0000

Merge branch 'fix/popover-performance' into 'develop'

Fix/popover performance

See merge request pleroma/pleroma-fe!1066

Diffstat:

MCHANGELOG.md1+
Mpackage.json1-
Msrc/components/account_actions/account_actions.js4+++-
Msrc/components/account_actions/account_actions.vue21++++++++++++---------
Msrc/components/emoji_reactions/emoji_reactions.js11++++-------
Msrc/components/emoji_reactions/emoji_reactions.vue33+++++++++++++++++++--------------
Msrc/components/extra_buttons/extra_buttons.js3+++
Msrc/components/extra_buttons/extra_buttons.vue14+++++++-------
Msrc/components/moderation_tools/moderation_tools.js11++++++++---
Msrc/components/moderation_tools/moderation_tools.vue17+++++++++--------
Asrc/components/popover/popover.js156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/components/popover/popover.vue118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/components/popper/popper.scss164-------------------------------------------------------------------------------
Msrc/components/react_button/react_button.js23+++++++----------------
Msrc/components/react_button/react_button.vue32+++++++++++++++-----------------
Msrc/components/status/status.vue11++++++++---
Msrc/components/status_popover/status_popover.js12++----------
Msrc/components/status_popover/status_popover.vue64+++++++++++++++++++++-------------------------------------------
Msrc/main.js8--------
Myarn.lock19-------------------
20 files changed, 393 insertions(+), 330 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md @@ -30,6 +30,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Registration fixed - Deactivation of remote accounts from frontend - Fixed NSFW unhiding not working with videos when using one-click unhiding/displaying +- Improved performance of anything that uses popovers (most notably statuses) ## [1.1.7 and earlier] - 2019-12-14 ### Added diff --git a/package.json b/package.json @@ -29,7 +29,6 @@ "portal-vue": "^2.1.4", "sanitize-html": "^1.13.0", "v-click-outside": "^2.1.1", - "v-tooltip": "^2.0.2", "vue": "^2.5.13", "vue-chat-scroll": "^1.2.1", "vue-i18n": "^7.3.2", diff --git a/src/components/account_actions/account_actions.js b/src/components/account_actions/account_actions.js @@ -1,4 +1,5 @@ import ProgressButton from '../progress_button/progress_button.vue' +import Popover from '../popover/popover.vue' const AccountActions = { props: [ @@ -8,7 +9,8 @@ const AccountActions = { return { } }, components: { - ProgressButton + ProgressButton, + Popover }, methods: { showRepeats () { diff --git a/src/components/account_actions/account_actions.vue b/src/components/account_actions/account_actions.vue @@ -1,13 +1,13 @@ <template> <div class="account-actions"> - <v-popover + <Popover trigger="click" - class="account-tools-popover" - :container="false" - placement="bottom-end" - :offset="5" + placement="bottom" > - <div slot="popover"> + <div + slot="content" + class="account-tools-popover" + > <div class="dropdown-menu"> <template v-if="user.following"> <button @@ -51,10 +51,13 @@ </button> </div> </div> - <div class="btn btn-default ellipsis-button"> + <div + slot="trigger" + class="btn btn-default ellipsis-button" + > <i class="icon-ellipsis trigger-button" /> </div> - </v-popover> + </Popover> </div> </template> @@ -62,7 +65,6 @@ <style lang="scss"> @import '../../_variables.scss'; -@import '../popper/popper.scss'; .account-actions { margin: 0 .8em; } @@ -70,6 +72,7 @@ .account-actions button.dropdown-item { margin-left: 0; } + .account-actions .trigger-button { color: $fallback--lightText; color: var(--lightText, $fallback--lightText); diff --git a/src/components/emoji_reactions/emoji_reactions.js b/src/components/emoji_reactions/emoji_reactions.js @@ -1,20 +1,17 @@ import UserAvatar from '../user_avatar/user_avatar.vue' +import Popover from '../popover/popover.vue' const EMOJI_REACTION_COUNT_CUTOFF = 12 const EmojiReactions = { name: 'EmojiReactions', components: { - UserAvatar + UserAvatar, + Popover }, props: ['status'], data: () => ({ - showAll: false, - popperOptions: { - modifiers: { - preventOverflow: { padding: { top: 50 }, boundariesElement: 'viewport' } - } - } + showAll: false }), computed: { tooManyReactions () { diff --git a/src/components/emoji_reactions/emoji_reactions.vue b/src/components/emoji_reactions/emoji_reactions.vue @@ -1,15 +1,14 @@ <template> <div class="emoji-reactions"> - <v-popover + <Popover v-for="(reaction) in emojiReactions" :key="reaction.name" - :popper-options="popperOptions" trigger="hover" placement="top" + :offset="{ y: 5 }" > - <div - slot="popover" + slot="content" class="reacted-users" > <div v-if="accountsForEmoji[reaction.name].length"> @@ -24,7 +23,12 @@ :compact="true" /> <div class="reacted-user-names"> - <span class="reacted-user-name" v-html="account.name_html" /> + <!-- eslint-disable vue/no-v-html --> + <span + class="reacted-user-name" + v-html="account.name_html" + /> + <!-- eslint-enable vue/no-v-html --> <span class="reacted-user-screen-name">{{ account.screen_name }}</span> </div> </div> @@ -34,6 +38,7 @@ </div> </div> <button + slot="trigger" class="emoji-reaction btn btn-default" :class="{ 'picked-reaction': reactedWith(reaction.name), 'not-clickable': !loggedIn }" @click="emojiOnClick(reaction.name, $event)" @@ -42,17 +47,16 @@ <span class="reaction-emoji">{{ reaction.name }}</span> <span>{{ reaction.count }}</span> </button> - </v-popover> + </Popover> <a - v-if="tooManyReactions" - @click="toggleShowAll" - class="emoji-reaction-expand faint" - href='javascript:void(0)' - > - {{ showAll ? $t('general.show_less') : showMoreString }} - </a> + v-if="tooManyReactions" + class="emoji-reaction-expand faint" + href="javascript:void(0)" + @click="toggleShowAll" + > + {{ showAll ? $t('general.show_less') : showMoreString }} + </a> </div> - </template> <script src="./emoji_reactions.js" ></script> @@ -78,6 +82,7 @@ display: flex; flex-direction: column; margin-left: 0.5em; + min-width: 5em; img { width: 1em; diff --git a/src/components/extra_buttons/extra_buttons.js b/src/components/extra_buttons/extra_buttons.js @@ -1,5 +1,8 @@ +import Popover from '../popover/popover.vue' + const ExtraButtons = { props: [ 'status' ], + components: { Popover }, methods: { deleteStatus () { const confirmed = window.confirm(this.$t('status.delete_confirm')) diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue @@ -1,11 +1,11 @@ <template> - <v-popover + <Popover v-if="canDelete || canMute || canPin" trigger="click" placement="top" class="extra-button-popover" > - <div slot="popover"> + <div slot="content"> <div class="dropdown-menu"> <button v-if="canMute && !status.thread_muted" @@ -47,17 +47,17 @@ </button> </div> </div> - <div class="button-icon"> - <i class="icon-ellipsis" /> - </div> - </v-popover> + <i + slot="trigger" + class="icon-ellipsis button-icon" + /> + </Popover> </template> <script src="./extra_buttons.js" ></script> <style lang="scss"> @import '../../_variables.scss'; -@import '../popper/popper.scss'; .icon-ellipsis { cursor: pointer; diff --git a/src/components/moderation_tools/moderation_tools.js b/src/components/moderation_tools/moderation_tools.js @@ -1,4 +1,5 @@ import DialogModal from '../dialog_modal/dialog_modal.vue' +import Popover from '../popover/popover.vue' const FORCE_NSFW = 'mrf_tag:media-force-nsfw' const STRIP_MEDIA = 'mrf_tag:media-strip' @@ -14,7 +15,6 @@ const ModerationTools = { ], data () { return { - showDropDown: false, tags: { FORCE_NSFW, STRIP_MEDIA, @@ -24,11 +24,13 @@ const ModerationTools = { SANDBOX, QUARANTINE }, - showDeleteUserDialog: false + showDeleteUserDialog: false, + toggled: false } }, components: { - DialogModal + DialogModal, + Popover }, computed: { tagsSet () { @@ -89,6 +91,9 @@ const ModerationTools = { window.history.back() } }) + }, + setToggled (value) { + this.toggled = value } } } diff --git a/src/components/moderation_tools/moderation_tools.vue b/src/components/moderation_tools/moderation_tools.vue @@ -1,13 +1,14 @@ <template> <div> - <v-popover + <Popover trigger="click" class="moderation-tools-popover" - placement="bottom-end" - @show="showDropDown = true" - @hide="showDropDown = false" + placement="bottom" + :offset="{ y: 5 }" + @show="setToggled(true)" + @close="setToggled(false)" > - <div slot="popover"> + <div slot="content"> <div class="dropdown-menu"> <span v-if="user.is_local"> <button @@ -122,12 +123,13 @@ </div> </div> <button + slot="trigger" class="btn btn-default btn-block" - :class="{ toggled: showDropDown }" + :class="{ toggled }" > {{ $t('user_card.admin_menu.moderation') }} </button> - </v-popover> + </Popover> <portal to="modal"> <DialogModal v-if="showDeleteUserDialog" @@ -160,7 +162,6 @@ <style lang="scss"> @import '../../_variables.scss'; -@import '../popper/popper.scss'; .menu-checkbox { float: right; diff --git a/src/components/popover/popover.js b/src/components/popover/popover.js @@ -0,0 +1,156 @@ + +const Popover = { + name: 'Popover', + props: { + // Action to trigger popover: either 'hover' or 'click' + trigger: String, + // Either 'top' or 'bottom' + placement: String, + // Takes object with properties 'x' and 'y', values of these can be + // 'container' for using offsetParent as boundaries for either axis + // or 'viewport' + boundTo: Object, + // Takes a top/bottom/left/right object, how much space to leave + // between boundary and popover element + margin: Object, + // Takes a x/y object and tells how many pixels to offset from + // anchor point on either axis + offset: Object, + // Additional styles you may want for the popover container + popoverClass: String + }, + data () { + return { + hidden: true, + styles: { opacity: 0 }, + oldSize: { width: 0, height: 0 } + } + }, + methods: { + updateStyles () { + if (this.hidden) { + this.styles = { + opacity: 0 + } + return + } + + // Popover will be anchored around this element, trigger ref is the container, so + // its children are what are inside the slot. Expect only one slot="trigger". + const anchorEl = (this.$refs.trigger && this.$refs.trigger.children[0]) || this.$el + 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 content = this.$refs.content + // Minor optimization, don't call a slow reflow call if we don't have to + const parentBounds = this.boundTo && + (this.boundTo.x === 'container' || this.boundTo.y === 'container') && + this.$el.offsetParent.getBoundingClientRect() + const margin = this.margin || {} + + // 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: 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: 0 + (margin.top || 50), + max: window.innerHeight - (margin.bottom || 5) + } + + let horizOffset = 0 + + // 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 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 + } + + // 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 + + const yOffset = (this.offset && this.offset.y) || 0 + const translateY = usingTop + ? -anchorEl.offsetHeight - yOffset - content.offsetHeight + : yOffset + + const xOffset = (this.offset && this.offset.x) || 0 + const translateX = (anchorEl.offsetWidth * 0.5) - content.offsetWidth * 0.5 + 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.floor(translateX)}px) translateY(${Math.floor(translateY)}px)` + } + }, + showPopover () { + if (this.hidden) this.$emit('show') + this.hidden = false + this.$nextTick(this.updateStyles) + }, + hidePopover () { + if (!this.hidden) this.$emit('close') + this.hidden = true + this.styles = { opacity: 0 } + }, + onMouseenter (e) { + if (this.trigger === 'hover') this.showPopover() + }, + onMouseleave (e) { + if (this.trigger === 'hover') this.hidePopover() + }, + onClick (e) { + if (this.trigger === 'click') { + if (this.hidden) { + this.showPopover() + } else { + this.hidePopover() + } + } + }, + onClickOutside (e) { + if (this.hidden) return + if (this.$el.contains(e.target)) return + this.hidePopover() + } + }, + updated () { + // Monitor changes to content size, update styles only when content sizes have changed, + // that should be the only time we need to move the popover box if we don't care about scroll + // or resize + const content = this.$refs.content + if (!content) return + if (this.oldSize.width !== content.offsetWidth || this.oldSize.height !== content.offsetHeight) { + this.updateStyles() + this.oldSize = { width: content.offsetWidth, height: content.offsetHeight } + } + }, + created () { + document.addEventListener('click', this.onClickOutside) + }, + destroyed () { + document.removeEventListener('click', this.onClickOutside) + this.hidePopover() + } +} + +export default Popover diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue @@ -0,0 +1,118 @@ +<template> + <div + @mouseenter="onMouseenter" + @mouseleave="onMouseleave" + > + <div + ref="trigger" + @click="onClick" + > + <slot name="trigger" /> + </div> + <div + v-if="!hidden" + ref="content" + :style="styles" + class="popover" + :class="popoverClass" + > + <slot + name="content" + class="popover-inner" + :close="hidePopover" + /> + </div> + </div> +</template> + +<script src="./popover.js" /> + +<style lang=scss> +@import '../../_variables.scss'; + +.popover { + z-index: 8; + position: absolute; + min-width: 0; + transition: opacity 0.3s; + + box-shadow: 1px 1px 4px rgba(0,0,0,.6); + box-shadow: var(--panelShadow); + border-radius: $fallback--btnRadius; + border-radius: var(--btnRadius, $fallback--btnRadius); + + background-color: $fallback--bg; + background-color: var(--popover, $fallback--bg); + color: $fallback--text; + color: var(--popoverText, $fallback--text); + --faint: var(--popoverFaintText, $fallback--faint); + --faintLink: var(--popoverFaintLink, $fallback--faint); + --lightText: var(--popoverLightText, $fallback--lightText); + --postLink: var(--popoverPostLink, $fallback--link); + --postFaintLink: var(--popoverPostFaintLink, $fallback--link); + --icon: var(--popoverIcon, $fallback--icon); +} + +.dropdown-menu { + display: block; + padding: .5rem 0; + font-size: 1rem; + text-align: left; + list-style: none; + max-width: 100vw; + z-index: 10; + white-space: nowrap; + + .dropdown-divider { + height: 0; + margin: .5rem 0; + overflow: hidden; + border-top: 1px solid $fallback--border; + border-top: 1px solid var(--border, $fallback--border); + } + + .dropdown-item { + line-height: 21px; + margin-right: 5px; + overflow: auto; + display: block; + padding: .25rem 1.0rem .25rem 1.5rem; + clear: both; + font-weight: 400; + text-align: inherit; + white-space: nowrap; + border: none; + border-radius: 0px; + background-color: transparent; + box-shadow: none; + width: 100%; + height: 100%; + + --btnText: var(--popoverText, $fallback--text); + + &-icon { + padding-left: 0.5rem; + + i { + margin-right: 0.25rem; + color: var(--menuPopoverIcon, $fallback--icon) + } + } + + &:active, &:hover { + background-color: $fallback--lightBg; + background-color: var(--selectedMenuPopover, $fallback--lightBg); + color: $fallback--link; + color: var(--selectedMenuPopoverText, $fallback--link); + --faint: var(--selectedMenuPopoverFaintText, $fallback--faint); + --faintLink: var(--selectedMenuPopoverFaintLink, $fallback--faint); + --lightText: var(--selectedMenuPopoverLightText, $fallback--lightText); + --icon: var(--selectedMenuPopoverIcon, $fallback--icon); + i { + color: var(--selectedMenuPopoverIcon, $fallback--icon); + } + } + + } +} +</style> diff --git a/src/components/popper/popper.scss b/src/components/popper/popper.scss @@ -1,164 +0,0 @@ -@import '../../_variables.scss'; - -.tooltip.popover { - z-index: 8; - - .popover-inner { - box-shadow: 1px 1px 4px rgba(0,0,0,.6); - box-shadow: var(--panelShadow); - border-radius: $fallback--btnRadius; - border-radius: var(--btnRadius, $fallback--btnRadius); - background-color: $fallback--bg; - background-color: var(--popover, $fallback--bg); - color: $fallback--text; - color: var(--popoverText, $fallback--text); - --faint: var(--popoverFaintText, $fallback--faint); - --faintLink: var(--popoverFaintLink, $fallback--faint); - --lightText: var(--popoverLightText, $fallback--lightText); - --postLink: var(--popoverPostLink, $fallback--link); - --postFaintLink: var(--popoverPostFaintLink, $fallback--link); - --icon: var(--popoverIcon, $fallback--icon); - } - - .popover-arrow { - width: 0; - height: 0; - border-style: solid; - position: absolute; - margin: 5px; - border-color: $fallback--bg; - border-color: var(--bg, $fallback--bg); - } - - &[x-placement^="top"] { - margin-bottom: 5px; - - .popover-arrow { - border-width: 5px 5px 0 5px; - border-left-color: transparent !important; - border-right-color: transparent !important; - border-bottom-color: transparent !important; - bottom: -4px; - left: calc(50% - 5px); - margin-top: 0; - margin-bottom: 0; - } - } - - &[x-placement^="bottom"] { - margin-top: 5px; - - .popover-arrow { - border-width: 0 5px 5px 5px; - border-left-color: transparent !important; - border-right-color: transparent !important; - border-top-color: transparent !important; - top: -4px; - left: calc(50% - 5px); - margin-top: 0; - margin-bottom: 0; - } - } - - &[x-placement^="right"] { - margin-left: 5px; - - .popover-arrow { - border-width: 5px 5px 5px 0; - border-left-color: transparent !important; - border-top-color: transparent !important; - border-bottom-color: transparent !important; - left: -4px; - top: calc(50% - 5px); - margin-left: 0; - margin-right: 0; - } - } - - &[x-placement^="left"] { - margin-right: 5px; - - .popover-arrow { - border-width: 5px 0 5px 5px; - border-top-color: transparent !important; - border-right-color: transparent !important; - border-bottom-color: transparent !important; - right: -4px; - top: calc(50% - 5px); - margin-left: 0; - margin-right: 0; - } - } - - &[aria-hidden='true'] { - visibility: hidden; - opacity: 0; - transition: opacity .15s, visibility .15s; - } - - &[aria-hidden='false'] { - visibility: visible; - opacity: 1; - transition: opacity .15s; - } -} - -.dropdown-menu { - display: block; - padding: .5rem 0; - font-size: 1rem; - text-align: left; - list-style: none; - max-width: 100vw; - z-index: 10; - - .dropdown-divider { - height: 0; - margin: .5rem 0; - overflow: hidden; - border-top: 1px solid $fallback--border; - border-top: 1px solid var(--border, $fallback--border); - } - - .dropdown-item { - line-height: 21px; - margin-right: 5px; - overflow: auto; - display: block; - padding: .25rem 1.0rem .25rem 1.5rem; - clear: both; - font-weight: 400; - text-align: inherit; - white-space: normal; - border: none; - border-radius: 0px; - background-color: transparent; - box-shadow: none; - width: 100%; - height: 100%; - - --btnText: var(--popoverText, $fallback--text); - - &-icon { - padding-left: 0.5rem; - - i { - margin-right: 0.25rem; - } - } - - &:active, &:hover { - background-color: $fallback--lightBg; - background-color: var(--selectedMenuPopover, $fallback--lightBg); - color: $fallback--link; - color: var(--selectedMenuPopoverText, $fallback--link); - --faint: var(--selectedMenuPopoverFaintText, $fallback--faint); - --faintLink: var(--selectedMenuPopoverFaintLink, $fallback--faint); - --lightText: var(--selectedMenuPopoverLightText, $fallback--lightText); - --icon: var(--selectedMenuPopoverIcon, $fallback--icon); - i { - color: var(--selectedMenuPopoverIcon, $fallback--icon); - } - } - } -} diff --git a/src/components/react_button/react_button.js b/src/components/react_button/react_button.js @@ -1,34 +1,25 @@ +import Popover from '../popover/popover.vue' import { mapGetters } from 'vuex' const ReactButton = { props: ['status', 'loggedIn'], data () { return { - showTooltip: false, - filterWord: '', - popperOptions: { - modifiers: { - preventOverflow: { padding: { top: 50 }, boundariesElement: 'viewport' } - } - } + filterWord: '' } }, + components: { + Popover + }, methods: { - openReactionSelect () { - this.showTooltip = true - this.filterWord = '' - }, - closeReactionSelect () { - this.showTooltip = false - }, - addReaction (event, emoji) { + addReaction (event, emoji, close) { const existingReaction = this.status.emoji_reactions.find(r => r.name === emoji) if (existingReaction && existingReaction.me) { this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji }) } else { this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji }) } - this.closeReactionSelect() + close() } }, computed: { diff --git a/src/components/react_button/react_button.vue b/src/components/react_button/react_button.vue @@ -1,13 +1,14 @@ <template> - <v-popover - :popper-options="popperOptions" - :open="showTooltip" - trigger="manual" + <Popover + trigger="click" placement="top" + :offset="{ y: 5 }" class="react-button-popover" - @hide="closeReactionSelect" > - <div slot="popover"> + <div + slot="content" + slot-scope="{close}" + > <div class="reaction-picker-filter"> <input v-model="filterWord" @@ -19,7 +20,7 @@ v-for="emoji in commonEmojis" :key="emoji" class="emoji-button" - @click="addReaction($event, emoji)" + @click="addReaction($event, emoji, close)" > {{ emoji }} </span> @@ -28,23 +29,20 @@ v-for="(emoji, key) in emojis" :key="key" class="emoji-button" - @click="addReaction($event, emoji.replacement)" + @click="addReaction($event, emoji.replacement, close)" > {{ emoji.replacement }} </span> <div class="reaction-bottom-fader" /> </div> </div> - <div + <i v-if="loggedIn" - @click.prevent="openReactionSelect" - > - <i - class="icon-smile button-icon add-reaction-button" - :title="$t('tool_tip.add_reaction')" - /> - </div> - </v-popover> + slot="trigger" + class="icon-smile button-icon add-reaction-button" + :title="$t('tool_tip.add_reaction')" + /> + </Popover> </template> <script src="./react_button.js" ></script> diff --git a/src/components/status/status.vue b/src/components/status/status.vue @@ -177,6 +177,8 @@ <StatusPopover v-if="!isPreview" :status-id="status.in_reply_to_status_id" + class="reply-to-popover" + style="min-width: 0" > <a class="reply-to" @@ -572,11 +574,10 @@ $status-margin: 0.75em; align-items: stretch; > .reply-to-and-accountname > a { + overflow: hidden; max-width: 100%; text-overflow: ellipsis; - overflow: hidden; white-space: nowrap; - display: inline-block; word-break: break-all; } } @@ -585,7 +586,6 @@ $status-margin: 0.75em; display: flex; height: 18px; margin-right: 0.5em; - overflow: hidden; max-width: 100%; .icon-reply { transform: scaleX(-1); @@ -596,6 +596,10 @@ $status-margin: 0.75em; display: flex; } + .reply-to-popover { + min-width: 0; + } + .reply-to { display: flex; } @@ -603,6 +607,7 @@ $status-margin: 0.75em; .reply-to-text { overflow: hidden; text-overflow: ellipsis; + white-space: nowrap; margin: 0 0.4em 0 0.2em; } diff --git a/src/components/status_popover/status_popover.js b/src/components/status_popover/status_popover.js @@ -5,22 +5,14 @@ const StatusPopover = { props: [ 'statusId' ], - data () { - return { - popperOptions: { - modifiers: { - preventOverflow: { padding: { top: 50 }, boundariesElement: 'viewport' } - } - } - } - }, computed: { status () { return find(this.$store.state.statuses.allStatuses, { id: this.statusId }) } }, components: { - Status: () => import('../status/status.vue') + Status: () => import('../status/status.vue'), + Popover: () => import('../popover/popover.vue') }, methods: { enter () { diff --git a/src/components/status_popover/status_popover.vue b/src/components/status_popover/status_popover.vue @@ -1,11 +1,16 @@ <template> - <v-popover + <Popover + trigger="hover" popover-class="status-popover" - placement="top-start" - :popper-options="popperOptions" - @show="enter()" + :bound-to="{ x: 'container' }" + @show="enter" > - <template slot="popover"> + <template slot="trigger"> + <slot /> + </template> + <div + slot="content" + > <Status v-if="status" :is-preview="true" @@ -18,10 +23,8 @@ > <i class="icon-spin4 animate-spin" /> </div> - </template> - - <slot /> - </v-popover> + </div> + </Popover> </template> <script src="./status_popover.js" ></script> @@ -29,44 +32,19 @@ <style lang="scss"> @import '../../_variables.scss'; -.tooltip.popover.status-popover { +.status-popover { font-size: 1rem; min-width: 15em; max-width: 95%; - margin-left: 0.5em; - - .popover-inner { - border-color: $fallback--border; - border-color: var(--border, $fallback--border); - border-style: solid; - 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); - } - .popover-arrow::before { - position: absolute; - content: ''; - left: -7px; - border: solid 7px transparent; - z-index: -1; - } - - &[x-placement^="bottom-start"] .popover-arrow::before { - top: -2px; - border-top-width: 0; - border-bottom-color: $fallback--border; - border-bottom-color: var(--border, $fallback--border); - } - - &[x-placement^="top-start"] .popover-arrow::before { - bottom: -2px; - border-bottom-width: 0; - border-top-color: $fallback--border; - border-top-color: var(--border, $fallback--border); - } + border-color: $fallback--border; + border-color: var(--border, $fallback--border); + border-style: solid; + 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); .status-el.status-el { border: none; diff --git a/src/main.js b/src/main.js @@ -31,7 +31,6 @@ import VueChatScroll from 'vue-chat-scroll' import VueClickOutside from 'v-click-outside' import PortalVue from 'portal-vue' import VBodyScrollLock from './directives/body_scroll_lock' -import VTooltip from 'v-tooltip' import afterStoreSetup from './boot/after_store.js' @@ -44,13 +43,6 @@ Vue.use(VueChatScroll) Vue.use(VueClickOutside) Vue.use(PortalVue) Vue.use(VBodyScrollLock) -Vue.use(VTooltip, { - popover: { - defaultTrigger: 'hover click', - defaultContainer: false, - defaultOffset: 5 - } -}) const i18n = new VueI18n({ // By default, use the browser locale, we will update it if neccessary diff --git a/yarn.lock b/yarn.lock @@ -5941,11 +5941,6 @@ pngjs@^3.3.0: version "3.3.3" resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.3.3.tgz#85173703bde3edac8998757b96e5821d0966a21b" -popper.js@^1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.15.0.tgz#5560b99bbad7647e9faa475c6b8056621f5a4ff2" - integrity sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA== - portal-vue@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/portal-vue/-/portal-vue-2.1.4.tgz#1fc679d77e294dc8d026f1eb84aa467de11b392e" @@ -7823,15 +7818,6 @@ v-click-outside@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/v-click-outside/-/v-click-outside-2.1.3.tgz#b7297abe833a439dc0895e6418a494381e64b5e7" -v-tooltip@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/v-tooltip/-/v-tooltip-2.0.2.tgz#8610d9eece2cc44fd66c12ef2f12eec6435cab9b" - integrity sha512-xQ+qzOFfywkLdjHknRPgMMupQNS8yJtf9Utd5Dxiu/0n4HtrxqsgDtN2MLZ0LKbburtSAQgyypuE/snM8bBZhw== - dependencies: - lodash "^4.17.11" - popper.js "^1.15.0" - vue-resize "^0.4.5" - validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -7906,11 +7892,6 @@ vue-loader@^14.0.0: vue-style-loader "^4.0.1" vue-template-es2015-compiler "^1.6.0" -vue-resize@^0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/vue-resize/-/vue-resize-0.4.5.tgz#4777a23042e3c05620d9cbda01c0b3cc5e32dcea" - integrity sha512-bhP7MlgJQ8TIkZJXAfDf78uJO+mEI3CaLABLjv0WNzr4CcGRGPIAItyWYnP6LsPA4Oq0WE+suidNs6dgpO4RHg== - vue-router@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.2.tgz#dedc67afe6c4e2bc25682c8b1c2a8c0d7c7e56be"