Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85807173
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
29 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/components/mention_link/mention_link.js b/src/components/mention_link/mention_link.js
index 5db90ab41c..88e691741f 100644
--- a/src/components/mention_link/mention_link.js
+++ b/src/components/mention_link/mention_link.js
@@ -1,165 +1,175 @@
import { mapState } from 'pinia'
import UnicodeDomainIndicator from 'src/components/unicode_domain_indicator/unicode_domain_indicator.vue'
import UserAvatar from 'src/components/user_avatar/user_avatar.vue'
import UserPopover from 'src/components/user_popover/user_popover.vue'
import {
highlightClass,
highlightStyle,
} from '../../services/user_highlighter/user_highlighter.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useUserHighlightStore } from 'src/stores/user_highlight.js'
import { useUsersStore } from 'src/stores/users.js'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faAt } from '@fortawesome/free-solid-svg-icons'
library.add(faAt)
const MentionLink = {
name: 'MentionLink',
components: {
UserAvatar,
UnicodeDomainIndicator,
UserPopover,
},
props: {
url: {
required: false,
type: String,
},
content: {
required: true,
type: String,
},
userId: {
required: false,
type: String,
},
userScreenName: {
required: false,
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() {
if (this.$refs.full) {
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 ? useUsersStore().findUserByUrl(this.url) : null
},
isYou() {
if (!this.currentUser) return false
return this.user === this.currentUser
},
userName() {
return this.user && this.userNameFullUi.split('@')[0]
},
serverName() {
// XXX assumed that domain does not contain @
return (
this.user &&
(this.userNameFullUi.split('@')[1] || useInstanceStore().instanceDomain)
)
},
userNameFull() {
return this.user?.screen_name
},
userNameFullUi() {
return this.user?.screen_name_ui
},
highlightData() {
return this.highlight[this.user?.screen_name]
},
highlightType() {
return this.highlightData && '-' + this.highlightData.type
},
highlightClass() {
return this.highlightData && highlightClass(this.user)
},
style() {
if (this.highlightData) {
const {
backgroundColor,
backgroundPosition,
backgroundImage,
...rest
} = highlightStyle(this.highlightData)
return rest
}
},
classnames() {
return [
{
'-you': this.isYou && this.shouldBoldenYou,
'-highlighted': !!this.highlightData,
'-has-selection': this.hasSelection,
+ '-with-tooltip': this.shouldShowTooltip,
},
+ 'short',
+ 'new',
this.highlightType,
]
},
+ popoverAttrs() {
+ return {
+ href: this.url,
+ style: this.style,
+ class: this.classnames,
+ }
+ },
isRemote() {
return this.userName !== this.userNameFull
},
shouldShowFullUserName() {
const conf = this.mergedConfig.mentionLinkDisplay
if (conf === 'short') {
return false
} else if (conf === 'full') {
return true
} else {
// full_for_remote
return this.isRemote
}
},
shouldShowTooltip() {
return this.mergedConfig.mentionLinkShowTooltip
},
shouldShowAvatar() {
return this.mergedConfig.mentionLinkShowAvatar
},
shouldShowYous() {
return this.mergedConfig.mentionLinkShowYous
},
shouldBoldenYou() {
return this.mergedConfig.mentionLinkBoldenYou
},
shouldFadeDomain() {
return this.mergedConfig.mentionLinkFadeDomain
},
...mapState(useMergedConfigStore, ['mergedConfig']),
...mapState(useUserHighlightStore, ['highlight']),
...mapState(useUsersStore, ['currentUser']),
},
}
export default MentionLink
diff --git a/src/components/mention_link/mention_link.vue b/src/components/mention_link/mention_link.vue
index 33f0d9db78..11db0b4157 100644
--- a/src/components/mention_link/mention_link.vue
+++ b/src/components/mention_link/mention_link.vue
@@ -1,70 +1,60 @@
<template>
<span
class="MentionLink"
>
- <!-- eslint-disable vue/no-v-html -->
<a
v-if="!user"
:href="url"
class="original"
target="_blank"
v-html="content"
- /><!-- eslint-enable vue/no-v-html -->
+ />
<UserPopover
v-else
:user-id="user.id"
:disabled="!shouldShowTooltip"
+ :trigger-attrs="popoverAttrs"
+ link
+ @click="onClick"
>
- <span
- v-if="user"
- class="new"
- :style="style"
- :class="classnames"
- >
- <a
- class="short"
- :class="{ '-with-tooltip': shouldShowTooltip }"
- :href="url"
- @click.prevent="onClick"
- >
- <!-- eslint-disable vue/no-v-html -->
- <UserAvatar
- v-if="shouldShowAvatar"
- class="mention-avatar"
- :user-id="user.id"
- /><span
- class="shortName"
- >@<span
- class="userName"
- v-html="userName"
- /><span
- v-if="shouldShowFullUserName"
- class="serverName"
- :class="{ '-faded': shouldFadeDomain }"
- v-html="'@' + serverName"
- /><UnicodeDomainIndicator
- v-if="shouldShowFullUserName"
- :user="user"
- />
- </span>
- <span
- v-if="isYou && shouldShowYous"
- :class="{ '-you': shouldBoldenYou }"
- > {{ ' ' + $t('status.you') }}</span>
- <!-- eslint-enable vue/no-v-html -->
- </a><span
- ref="full"
- class="full"
- >
- <!-- eslint-disable vue/no-v-html -->
- @<span v-html="userName" /><span v-html="'@' + serverName" />
- <!-- eslint-enable vue/no-v-html -->
- </span>
+ <UserAvatar
+ v-if="shouldShowAvatar"
+ class="mention-avatar"
+ :user-id="user.id"
+ /><span
+ class="shortName"
+ >@<span
+ class="userName"
+ v-html="userName"
+ /><span
+ v-if="shouldShowFullUserName"
+ class="serverName"
+ :class="{ '-faded': shouldFadeDomain }"
+ v-html="'@' + serverName"
+ /><UnicodeDomainIndicator
+ v-if="shouldShowFullUserName"
+ :user="user"
+ />
</span>
+ <span
+ v-if="isYou && shouldShowYous"
+ :class="{ '-you': shouldBoldenYou }"
+ > {{ ' ' + $t('status.you') }}</span>
+ <!-- eslint-enable vue/no-v-html -->
</UserPopover>
+ <span
+ v-if="user"
+ ref="full"
+ class="full"
+ aria-hidden="true"
+ >
+ <!-- eslint-disable vue/no-v-html -->
+ @<span v-html="userName" /><span v-html="'@' + serverName" />
+ <!-- eslint-enable vue/no-v-html -->
+ </span>
</span>
</template>
<script src="./mention_link.js" />
<style lang="scss" src="./mention_link.scss" />
diff --git a/src/components/mentions_line/mentions_line.scss b/src/components/mentions_line/mentions_line.scss
index 30f2422ed0..2a5925453f 100644
--- a/src/components/mentions_line/mentions_line.scss
+++ b/src/components/mentions_line/mentions_line.scss
@@ -1,14 +1,10 @@
.MentionsLine {
overflow-wrap: break-word;
text-wrap: pretty;
- .mention-link:not(:first-child)::before {
- content: " ";
- }
-
.showMoreLess {
margin-left: 0.5em;
white-space: normal;
color: var(--link);
}
}
diff --git a/src/components/mentions_line/mentions_line.vue b/src/components/mentions_line/mentions_line.vue
index daab64a300..6b2ae75a49 100644
--- a/src/components/mentions_line/mentions_line.vue
+++ b/src/components/mentions_line/mentions_line.vue
@@ -1,40 +1,54 @@
<template>
<span class="MentionsLine">
- <MentionLink
+ <template
v-for="mention in mentionsComputed"
:key="mention.index"
- class="mention-link"
- :content="mention.content"
- :url="mention.url"
- /><span
+ >
+ <MentionLink
+ class="mention-link"
+ :content="mention.content"
+ :url="mention.url"
+ />
+ <template v-if="mention.index !== mentionsComputed.length - 1">
+ {{ ' ' }}
+ </template>
+ </template>
+ <span
v-if="manyMentions"
class="extraMentions"
>
+ {{ ' ' }}
<span
v-if="expanded"
class="fullExtraMentions"
- >{{ ' ' }}<MentionLink
+ >
+ <template
v-for="mention in extraMentions"
:key="mention.index"
- class="mention-link"
- :content="mention.content"
- :url="mention.url"
- />
+ >
+ <MentionLink
+ class="mention-link"
+ :content="mention.content"
+ :url="mention.url"
+ /><template v-if="mention.index === mentionsExtra.length - 1">
+ {{ ' ' }}
+ </template>
+ </template>
</span><button
v-if="!expanded"
class="button-unstyled -link showMoreLess"
@click="toggleShowMore"
>
{{ $t('status.plus_more', { number: extraMentions.length }) }}
</button><button
v-if="expanded"
class="button-unstyled -link showMoreLess"
@click="toggleShowMore"
>
{{ $t('general.show_less') }}
</button>
</span>
</span>
</template>
<script src="./mentions_line.js"></script>
<style lang="scss" src="./mentions_line.scss" />
diff --git a/src/components/popover/popover.js b/src/components/popover/popover.js
index e3c9d0f166..49a98dc8ec 100644
--- a/src/components/popover/popover.js
+++ b/src/components/popover/popover.js
@@ -1,424 +1,439 @@
/* global process */
const Popover = {
name: 'Popover',
props: {
// Action to trigger popover: either 'hover' or 'click'
trigger: String,
// 'top', 'bottom', 'left', 'right'
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 selector to use as a replacement for the parent container
// for getting boundaries for x an y axis
boundToSelector: String,
// 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,
// Replaces the classes you may want for the popover container.
// Use 'popover-default' in addition to get the default popover
// styles with your custom class.
popoverClass: String,
// 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,
// 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,
// Use styled button (to avoid nested buttons)
normalButton: Boolean,
+ // Use <a> instead of <button>
+ link: {
+ type: Boolean,
+ default: false,
+ },
+
// Whether to hide the trigger totally
hideTrigger: {
type: Boolean,
default: false,
},
triggerAttrs: {
type: Object,
default: {},
},
// Used to set or unset aria-haspopup (attribute not set for tooltips)
tooltip: Boolean,
},
inject: {
// override popover z layer
popoversZLayer: {
default: '',
},
},
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
anchorEl: null,
// There's an issue where having teleport enabled by default causes things just...
// not render at all, i.e. main post status form and its emoji inputs
teleport: false,
lockReEntry: false,
hidden: true,
styles: {},
oldSize: { width: 0, height: 0 },
scrollable: null,
// used to avoid blinking if hovered onto popover
graceTimeout: null,
parentPopover: null,
disableClickOutside: false,
childrenShown: new Set(),
}
},
computed: {
allTriggerAttrs() {
if (process.env.NODE_ENV === 'development') {
if ('aria-hidden' in this.triggerAttrs) {
throw new Error(
'Do not use aria-hidden in triggerAttrs. Instead set hideTrigger to true',
)
}
}
const attrs = {
...this.triggerAttrs,
}
if (this.hideTrigger) {
attrs['aria-hidden'] = true
attrs.tabindex = 1
}
return attrs
},
+ triggerClass() {
+ if (this.link) {
+ return ''
+ } else if (this.normalButton) {
+ return 'button-default btn'
+ } else {
+ return 'button-unstyled'
+ }
+ },
},
methods: {
setAnchorEl(el) {
this.anchorEl = el
this.updateStyles()
},
containerBoundingClientRect() {
const container = this.boundToSelector
? this.$el.closest(this.boundToSelector)
: this.$el.offsetParent
return container.getBoundingClientRect()
},
updateStyles() {
if (this.hidden) {
this.styles = {}
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 v-slot:trigger.
const anchorEl =
this.anchorEl || this.$refs.trigger?.children[0] || this.$el
// SVGs don't have offsetWidth/Height, use fallback
const anchorHeight = anchorEl.offsetHeight || anchorEl.clientHeight
const anchorWidth = anchorEl.offsetWidth || anchorEl.clientWidth
const anchorScreenBox = anchorEl.getBoundingClientRect()
const anchorStyle = getComputedStyle(anchorEl)
const topPadding = Number.parseFloat(anchorStyle.paddingTop)
const bottomPadding = Number.parseFloat(anchorStyle.paddingBottom)
const rightPadding = Number.parseFloat(anchorStyle.paddingRight)
const leftPadding = Number.parseFloat(anchorStyle.paddingLeft)
// 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 parentScreenBox =
(this.boundTo?.x === 'container' || this.boundTo?.y === 'container') &&
this.containerBoundingClientRect()
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?.x === 'container'
? {
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?.y === 'container'
? {
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 (leftBorder < xBounds.min) {
horizOffset += xBounds.min - leftBorder
}
// If overflowing from right, move it so that it doesn't
if (rightBorder > xBounds.max) {
horizOffset -= rightBorder - xBounds.max
}
// If overflowing from top, move it so that it doesn't
if (topBorder < yBounds.min) {
vertOffset += yBounds.min - topBorder
}
// If overflowing from bottom, move it so that it doesn't
if (bottomBorder > yBounds.max) {
vertOffset -= bottomBorder - yBounds.max
}
let translateX = 0
let translateY = 0
if (overlayCenter) {
translateX = origin.x + horizOffset
translateY = origin.y + vertOffset
} else if (this.placement !== 'right' && this.placement !== 'left') {
// 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 no space on bottom,
// regardless of what placement value was. Then check if there's no 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 yOffset = this.offset?.y || 0
translateY = usingTop
? topBoundary - yOffset - content.offsetHeight
: bottomBoundary + yOffset
const xOffset = this.offset?.x || 0
translateX = origin.x + horizOffset + xOffset
} else {
// Default to whatever user wished with placement prop
let usingLeft = this.placement !== 'right'
// Handle special cases, first force to displaying on left if there's no space on right,
// regardless of what placement value was. Then check if there's no space on right, and
// force to left, again regardless of what placement value was.
const leftBoundary =
origin.x - anchorWidth * 0.5 + (this.removePadding ? leftPadding : 0)
const rightBoundary =
origin.x + anchorWidth * 0.5 - (this.removePadding ? rightPadding : 0)
if (rightBoundary + content.offsetWidth > xBounds.max) usingLeft = true
if (leftBoundary - content.offsetWidth < xBounds.min) usingLeft = false
const xOffset = this.offset?.x || 0
translateX = usingLeft
? leftBoundary - xOffset - content.offsetWidth
: rightBoundary + xOffset
const yOffset = this.offset?.y || 0
translateY = origin.y + vertOffset + yOffset
}
this.styles = {
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
this.disableClickOutside = true
setTimeout(() => {
this.disableClickOutside = false
}, 0)
const wasHidden = this.hidden
this.hidden = false
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)
// My assumption is that upon showing popover initially has different size
// as its contents are getting populating, so logic uses those incorrect
// sizes as basis
setTimeout(() => {
if (wasHidden) this.$emit('show')
this.updateStyles()
}, 1)
},
hidePopover() {
if (this.disabled) return
if (!this.hidden) this.$emit('close')
this.hidden = true
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)
},
resizePopover() {
setTimeout(() => {
this.updateStyles()
}, 1)
},
onMouseenter() {
if (this.trigger === 'hover') {
this.lockReEntry = false
clearTimeout(this.graceTimeout)
this.graceTimeout = null
this.showPopover()
}
},
onMouseleave() {
if (this.trigger === 'hover' && this.childrenShown.size === 0) {
this.graceTimeout = setTimeout(() => this.hidePopover(), 1)
}
},
onMouseenterContent() {
if (this.trigger === 'hover' && !this.lockReEntry) {
this.lockReEntry = true
clearTimeout(this.graceTimeout)
this.graceTimeout = null
this.showPopover()
}
},
onMouseleaveContent() {
if (this.trigger === 'hover' && this.childrenShown.size === 0) {
this.graceTimeout = setTimeout(() => this.hidePopover(), 1)
}
},
onClick() {
if (this.trigger === 'click') {
if (this.hidden) {
this.showPopover()
} else {
this.hidePopover()
}
}
},
onClickOutside(e) {
if (this.disableClickOutside) return
if (this.hidden) return
if (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() {
this.updateStyles()
},
onResize() {
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,
}
}
},
onChildPopoverState(childRef, state) {
if (state) {
this.childrenShown.add(childRef)
} else {
this.childrenShown.delete(childRef)
}
},
},
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
this.onResize()
},
mounted() {
this.teleport = true
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
},
beforeUnmount() {
this.hidePopover()
},
}
export default Popover
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 905e5bca48..f5116c0745 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -1,48 +1,49 @@
<template>
<span
class="popover-wrapper"
role="presentation"
@mouseenter="onMouseenter"
@mouseleave="onMouseleave"
>
- <button
+ <component
ref="trigger"
+ :is="link ? 'a' : 'button'"
class="popover-trigger-button"
- :class="normalButton ? 'button-default btn' : 'button-unstyled'"
+ :class="triggerClass"
type="button"
v-bind="allTriggerAttrs"
- :aria-haspopup="tooltip ? undefined : true"
- @click="onClick"
+ :aria-haspopup="tooltip ? undefined : !disabled"
+ @click.prevent="onClick"
>
<slot name="trigger" />
- </button>
+ </component>
<teleport
:disabled="!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"
:resize="resizePopover"
/>
</div>
</transition>
</teleport>
</span>
</template>
<script src="./popover.js" />
<style src="./popover.scss" lang="scss"></style>
diff --git a/src/components/user_popover/user_popover.js b/src/components/user_popover/user_popover.js
index 67c75be501..6a9abf11ea 100644
--- a/src/components/user_popover/user_popover.js
+++ b/src/components/user_popover/user_popover.js
@@ -1,22 +1,22 @@
import { mapState } from 'pinia'
import Popover from 'src/components/popover/popover.vue'
import UserCard from 'src/components/user_card/user_card.vue'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
const UserPopover = {
name: 'UserPopover',
- props: ['userId', 'overlayCenters', 'disabled', 'overlayCentersSelector'],
+ props: ['userId', 'overlayCenters', 'overlayCentersSelector'],
components: {
UserCard,
Popover,
},
computed: mapState(useMergedConfigStore, {
userPopoverAvatarAction: (state) =>
state.mergedConfig.userPopoverAvatarAction,
userPopoverOverlay: (state) => state.mergedConfig.userPopoverOverlay,
}),
}
export default UserPopover
diff --git a/src/components/user_popover/user_popover.vue b/src/components/user_popover/user_popover.vue
index 0d8a4c550e..888c928482 100644
--- a/src/components/user_popover/user_popover.vue
+++ b/src/components/user_popover/user_popover.vue
@@ -1,54 +1,54 @@
<template>
<Popover
trigger="click"
popover-class="popover-default user-popover"
:overlay-centers-selector="overlayCentersSelector || '.user-info .Avatar'"
:overlay-centers="overlayCenters && userPopoverOverlay"
- :disabled="disabled"
+ v-bind="$attrs"
>
<template #trigger>
<slot />
</template>
<template #content="{close}">
<UserCard
class="user-popover"
:compact="true"
:show-close="true"
:show-expand="true"
:user-id="userId"
:hide-bio="true"
:avatar-action="userPopoverAvatarAction == 'close' ? close : userPopoverAvatarAction"
@close="close"
/>
</template>
</Popover>
</template>
<script src="./user_popover.js"></script>
<style lang="scss">
/* popover styles load on-demand, so we need to override */
/* stylelint-disable block-no-empty */
.user-popover {
margin: 0;
.user-info {
width: 100%;
margin: 1.2em;
}
.user-identity {
min-width: calc(min(30em, 98vw));
}
.user-card-inner {
display: flex;
}
&.popover {
overflow: hidden;
}
}
/* stylelint-enable block-no-empty */
</style>
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, Oct 14, 2:05 AM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1786971
Default Alt Text
(29 KB)
Attached To
Mode
rPUFE pleroma-fe-upstream
Attached
Detach File
Event Timeline
Log In to Comment