Page MenuHomePhorge

No OneTemporary

Size
10 KB
Referenced Files
None
Subscribers
None
diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue
index 8dc37d2b6c..3a7f1283ab 100644
--- a/src/components/extra_buttons/extra_buttons.vue
+++ b/src/components/extra_buttons/extra_buttons.vue
@@ -1,73 +1,71 @@
<template>
<Popover
v-if="canDelete || canMute || canPin"
trigger="click"
placement="top"
class="extra-button-popover"
>
<div slot="content">
<div class="dropdown-menu">
<button
v-if="canMute && !status.thread_muted"
class="dropdown-item dropdown-item-icon"
@click.prevent="muteConversation"
>
<i class="icon-eye-off" /><span>{{ $t("status.mute_conversation") }}</span>
</button>
<button
v-if="canMute && status.thread_muted"
class="dropdown-item dropdown-item-icon"
@click.prevent="unmuteConversation"
>
<i class="icon-eye-off" /><span>{{ $t("status.unmute_conversation") }}</span>
</button>
<button
v-if="!status.pinned && canPin"
v-close-popover
class="dropdown-item dropdown-item-icon"
@click.prevent="pinStatus"
>
<i class="icon-pin" /><span>{{ $t("status.pin") }}</span>
</button>
<button
v-if="status.pinned && canPin"
v-close-popover
class="dropdown-item dropdown-item-icon"
@click.prevent="unpinStatus"
>
<i class="icon-pin" /><span>{{ $t("status.unpin") }}</span>
</button>
<button
v-if="canDelete"
v-close-popover
class="dropdown-item dropdown-item-icon"
@click.prevent="deleteStatus"
>
<i class="icon-cancel" /><span>{{ $t("status.delete") }}</span>
</button>
</div>
</div>
- <div
+ <i
slot="trigger"
- class="button-icon"
- >
- <i class="icon-ellipsis" />
- </div>
+ class="icon-ellipsis button-icon"
+ />
</Popover>
</template>
<script src="./extra_buttons.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
.icon-ellipsis {
cursor: pointer;
&:hover,
.extra-button-popover.open & {
color: $fallback--text;
color: var(--text, $fallback--text);
}
}
</style>
diff --git a/src/components/popover/popover.js b/src/components/popover/popover.js
index 3732c42ef6..0640166629 100644
--- a/src/components/popover/popover.js
+++ b/src/components/popover/popover.js
@@ -1,143 +1,144 @@
const Popover = {
name: 'Popover',
props: [
'trigger',
'placement',
'boundTo',
'padding',
'offset',
'popoverClass'
],
data () {
return {
hidden: true,
styles: { opacity: 0 },
oldSize: { width: 0, height: 0 }
}
},
computed: {
display () {
return !this.hidden
}
},
methods: {
updateStyles () {
if (this.hidden) return { opacity: 0 }
- // Popover will be anchored around this element
- const anchorEl = this.$refs.trigger || this.$el
+ // 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 padding = this.padding || {}
// What are the screen bounds for the popover? Viewport vs container
// when using viewport, using default padding values to dodge the navbar
const xBounds = this.boundTo && this.boundTo.x === 'container' ? {
min: parentBounds.left + (padding.left || 0),
max: parentBounds.right - (padding.right || 0)
} : {
min: 0 + (padding.left || 10),
max: window.innerWidth - (padding.right || 10)
}
const yBounds = this.boundTo && this.boundTo.y === 'container' ? {
min: parentBounds.top + (padding.top || 0),
max: parentBounds.bottom - (padding.bottom || 0)
} : {
min: 0 + (padding.top || 50),
max: window.innerHeight - (padding.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 + yOffset
const xOffset = (this.offset && this.offset.x) || 0
const translateX = (anchorEl.offsetWidth * 0.5) - content.offsetWidth * 0.5 + horizOffset + xOffset
this.styles = {
opacity: 1,
- transform: `translate(${Math.floor(translateX)}px, ${Math.floor(translateY)}px)`
+ transform: `translate(${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/react_button/react_button.vue b/src/components/react_button/react_button.vue
index 8613143fdb..ab4b4fcd09 100644
--- a/src/components/react_button/react_button.vue
+++ b/src/components/react_button/react_button.vue
@@ -1,113 +1,111 @@
<template>
<Popover
trigger="click"
placement="top"
+ :offset="{ y: 5 }"
class="react-button-popover"
>
<div
slot="content"
slot-scope="{close}"
>
<div class="reaction-picker-filter">
<input
v-model="filterWord"
:placeholder="$t('emoji.search_emoji')"
>
</div>
<div class="reaction-picker">
<span
v-for="emoji in commonEmojis"
:key="emoji"
class="emoji-button"
@click="addReaction($event, emoji, close)"
>
{{ emoji }}
</span>
<div class="reaction-picker-divider" />
<span
v-for="(emoji, key) in emojis"
:key="key"
class="emoji-button"
@click="addReaction($event, emoji.replacement, close)"
>
{{ emoji.replacement }}
</span>
<div class="reaction-bottom-fader" />
</div>
</div>
- <div
+ <i
v-if="loggedIn"
slot="trigger"
- >
- <i
- class="icon-smile button-icon add-reaction-button"
- :title="$t('tool_tip.add_reaction')"
- />
- </div>
+ class="icon-smile button-icon add-reaction-button"
+ :title="$t('tool_tip.add_reaction')"
+ />
</Popover>
</template>
<script src="./react_button.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
.reaction-picker-filter {
padding: 0.5em;
display: flex;
input {
flex: 1;
}
}
.reaction-picker-divider {
height: 1px;
width: 100%;
margin: 0.5em;
background-color: var(--border, $fallback--border);
}
.reaction-picker {
width: 10em;
height: 9em;
font-size: 1.5em;
overflow-y: scroll;
display: flex;
flex-wrap: wrap;
padding: 0.5em;
text-align: center;
align-content: flex-start;
user-select: none;
mask: linear-gradient(to top, white 0, transparent 100%) bottom no-repeat,
linear-gradient(to bottom, white 0, transparent 100%) top no-repeat,
linear-gradient(to top, white, white);
transition: mask-size 150ms;
mask-size: 100% 20px, 100% 20px, auto;
// Autoprefixed seem to ignore this one, and also syntax is different
-webkit-mask-composite: xor;
mask-composite: exclude;
.emoji-button {
cursor: pointer;
flex-basis: 20%;
line-height: 1.5em;
align-content: center;
&:hover {
transform: scale(1.25);
}
}
}
.add-reaction-button {
cursor: pointer;
&:hover {
color: $fallback--text;
color: var(--text, $fallback--text);
}
}
</style>

File Metadata

Mime Type
text/x-diff
Expires
Fri, Oct 9, 7:57 AM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1784534
Default Alt Text
(10 KB)

Event Timeline