rewrite popover because v-tooltip is slow as heck
This commit is contained in:
parent
8fcb9c42aa
commit
5262676e0e
13 changed files with 417 additions and 168 deletions
|
@ -12,6 +12,7 @@ import MobilePostStatusButton from './components/mobile_post_status_button/mobil
|
||||||
import MobileNav from './components/mobile_nav/mobile_nav.vue'
|
import MobileNav from './components/mobile_nav/mobile_nav.vue'
|
||||||
import UserReportingModal from './components/user_reporting_modal/user_reporting_modal.vue'
|
import UserReportingModal from './components/user_reporting_modal/user_reporting_modal.vue'
|
||||||
import PostStatusModal from './components/post_status_modal/post_status_modal.vue'
|
import PostStatusModal from './components/post_status_modal/post_status_modal.vue'
|
||||||
|
import PopoverTarget from './components/popover/popover_target.vue'
|
||||||
import { windowWidth } from './services/window_utils/window_utils'
|
import { windowWidth } from './services/window_utils/window_utils'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -30,7 +31,8 @@ export default {
|
||||||
MobilePostStatusButton,
|
MobilePostStatusButton,
|
||||||
MobileNav,
|
MobileNav,
|
||||||
UserReportingModal,
|
UserReportingModal,
|
||||||
PostStatusModal
|
PostStatusModal,
|
||||||
|
PopoverTarget
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
mobileActivePanel: 'timeline',
|
mobileActivePanel: 'timeline',
|
||||||
|
|
|
@ -123,6 +123,7 @@
|
||||||
<UserReportingModal />
|
<UserReportingModal />
|
||||||
<PostStatusModal />
|
<PostStatusModal />
|
||||||
<portal-target name="modal" />
|
<portal-target name="modal" />
|
||||||
|
<PopoverTarget />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
import Popover from '../popover/popover.vue'
|
||||||
|
|
||||||
const ExtraButtons = {
|
const ExtraButtons = {
|
||||||
props: [ 'status' ],
|
props: [ 'status' ],
|
||||||
|
components: { Popover },
|
||||||
methods: {
|
methods: {
|
||||||
deleteStatus () {
|
deleteStatus () {
|
||||||
const confirmed = window.confirm(this.$t('status.delete_confirm'))
|
const confirmed = window.confirm(this.$t('status.delete_confirm'))
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<v-popover
|
<Popover
|
||||||
v-if="canDelete || canMute || canPin"
|
v-if="canDelete || canMute || canPin"
|
||||||
trigger="click"
|
trigger="click"
|
||||||
placement="top"
|
placement="bottom"
|
||||||
class="extra-button-popover"
|
class="extra-button-popover"
|
||||||
>
|
>
|
||||||
<div slot="popover">
|
<div slot="content">
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<button
|
<button
|
||||||
v-if="canMute && !status.thread_muted"
|
v-if="canMute && !status.thread_muted"
|
||||||
|
@ -47,10 +47,10 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="button-icon">
|
<div slot="trigger" class="button-icon">
|
||||||
<i class="icon-ellipsis" />
|
<i class="icon-ellipsis" />
|
||||||
</div>
|
</div>
|
||||||
</v-popover>
|
</Popover>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./extra_buttons.js" ></script>
|
<script src="./extra_buttons.js" ></script>
|
||||||
|
@ -59,6 +59,10 @@
|
||||||
@import '../../_variables.scss';
|
@import '../../_variables.scss';
|
||||||
@import '../popper/popper.scss';
|
@import '../popper/popper.scss';
|
||||||
|
|
||||||
|
.dropdown-menu {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.icon-ellipsis {
|
.icon-ellipsis {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
|
113
src/components/popover/popover.js
Normal file
113
src/components/popover/popover.js
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
|
||||||
|
const Popover = {
|
||||||
|
name: 'Popover',
|
||||||
|
props: [
|
||||||
|
'trigger',
|
||||||
|
'placement',
|
||||||
|
'show'
|
||||||
|
],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
hidden: true,
|
||||||
|
styles: { opacity: 0 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
display () {
|
||||||
|
return !this.hidden
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/*
|
||||||
|
registerPopover (e) {
|
||||||
|
if (!this.targetId) {
|
||||||
|
this.$store.dispatch('registerPopover', e.target).then(id => this.targetId = id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
unregisterPopover () {
|
||||||
|
if (this.targetId) {
|
||||||
|
this.$store.dispatch('unregisterPopover', this.targetId)
|
||||||
|
this.targetId = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
showPopover () {
|
||||||
|
this.hidden = false
|
||||||
|
this.$nextTick(function () {
|
||||||
|
if (this.hidden) return { opacity: 0 }
|
||||||
|
|
||||||
|
const anchorEl = this.$refs.trigger || this.$el
|
||||||
|
console.log(anchorEl)
|
||||||
|
const screenBox = anchorEl.getBoundingClientRect()
|
||||||
|
const origin = { x: screenBox.left + screenBox.width * 0.5, y: screenBox.top}
|
||||||
|
const content = this.$refs.content
|
||||||
|
let horizOffset = 0
|
||||||
|
|
||||||
|
if ((origin.x - content.offsetWidth * 0.5) < 25) {
|
||||||
|
horizOffset += -(origin.x - content.offsetWidth * 0.5) + 25
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log((origin.x + content.offsetWidth * 0.5), (window.innerWidth - 25))
|
||||||
|
if ((origin.x + content.offsetWidth * 0.5) > window.innerWidth - 25) {
|
||||||
|
horizOffset -= (origin.x + content.offsetWidth * 0.5) - (window.innerWidth - 25)
|
||||||
|
}
|
||||||
|
// 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 > (window.innerHeight - 25)) usingTop = true
|
||||||
|
if (origin.y - content.offsetHeight < 50) usingTop = false
|
||||||
|
|
||||||
|
const vertAlign = usingTop ?
|
||||||
|
{
|
||||||
|
bottom: `${anchorEl.offsetHeight}px`
|
||||||
|
} :
|
||||||
|
{
|
||||||
|
top: `${anchorEl.offsetHeight}px`
|
||||||
|
}
|
||||||
|
this.styles = {
|
||||||
|
opacity: '100%',
|
||||||
|
left: `${(anchorEl.offsetLeft + anchorEl.offsetWidth * 0.5) - content.offsetWidth * 0.5 + horizOffset}px`,
|
||||||
|
...vertAlign
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
hidePopover () {
|
||||||
|
this.hidden = true
|
||||||
|
this.styles = { opacity: 0 }
|
||||||
|
},
|
||||||
|
onMouseenter (e) {
|
||||||
|
console.log(this.trigger)
|
||||||
|
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
|
||||||
|
console.log(e.target)
|
||||||
|
this.hidePopover()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
document.addEventListener("click", this.onClickOutside)
|
||||||
|
},
|
||||||
|
destroyed () {
|
||||||
|
document.removeEventListener("click", this.onClickOutside)
|
||||||
|
this.hidePopover()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Popover
|
195
src/components/popover/popover.vue
Normal file
195
src/components/popover/popover.vue
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
<template>
|
||||||
|
<!-- This is for the weird portal shit
|
||||||
|
<div
|
||||||
|
@mouseenter="registerPopover"
|
||||||
|
@mouseleave="unregisterPopover"
|
||||||
|
>
|
||||||
|
<slot name="trigger"></slot>
|
||||||
|
<portal
|
||||||
|
v-if="targetId"
|
||||||
|
:to="targetId"
|
||||||
|
>
|
||||||
|
<slot name="content"></slot>
|
||||||
|
</portal>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
<div
|
||||||
|
@mouseenter="onMouseenter"
|
||||||
|
@mouseleave="onMouseleave"
|
||||||
|
>
|
||||||
|
<div @click="onClick" ref="trigger">
|
||||||
|
<slot name="trigger"></slot>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="display"
|
||||||
|
:style="styles"
|
||||||
|
class="popover"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
ref="content"
|
||||||
|
class="popover-inner"
|
||||||
|
>
|
||||||
|
<!-- onSuccess is to mimic basic functionality of v-popover -->
|
||||||
|
<slot
|
||||||
|
name="content"
|
||||||
|
@onSuccess="hidePopover"
|
||||||
|
></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./popover.js" />
|
||||||
|
|
||||||
|
<style lang=scss>
|
||||||
|
@import '../../_variables.scss';
|
||||||
|
|
||||||
|
.popover {
|
||||||
|
z-index: 8;
|
||||||
|
position: absolute;
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
|
.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(--bg, $fallback--bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
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%;
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
padding-left: 0.5rem;
|
||||||
|
|
||||||
|
i {
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
// TODO: improve the look on breeze themes
|
||||||
|
background-color: $fallback--fg;
|
||||||
|
background-color: var(--btn, $fallback--fg);
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
23
src/components/popover/popover_target.js
Normal file
23
src/components/popover/popover_target.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
const PopoverTarget = {
|
||||||
|
name: 'PopoverTarget',
|
||||||
|
computed: {
|
||||||
|
ids () {
|
||||||
|
const popovers = this.$store.state.popover.popovers
|
||||||
|
return Object.keys(popovers)
|
||||||
|
},
|
||||||
|
styles () {
|
||||||
|
return this.ids.reduce((acc, id) => {
|
||||||
|
const el = this.$store.state.popover.popovers[id]
|
||||||
|
const box = el.getBoundingClientRect()
|
||||||
|
acc[id] = {
|
||||||
|
top: `${box.y}px`,
|
||||||
|
left: `${box.x}px`
|
||||||
|
}
|
||||||
|
console.log(acc)
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PopoverTarget
|
25
src/components/popover/popover_target.vue
Normal file
25
src/components/popover/popover_target.vue
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<template>
|
||||||
|
<div class="popover-targets">
|
||||||
|
<portal-target
|
||||||
|
v-for="id in ids"
|
||||||
|
:key="id"
|
||||||
|
:name="id"
|
||||||
|
:style="styles[id]"
|
||||||
|
class="popover-target"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script src="./popover_target.js" />
|
||||||
|
<style lang="scss">
|
||||||
|
|
||||||
|
.popover-targets {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover-target {
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
|
@ -1,147 +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(--bg, $fallback--bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.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%;
|
|
||||||
|
|
||||||
&-icon {
|
|
||||||
padding-left: 0.5rem;
|
|
||||||
|
|
||||||
i {
|
|
||||||
margin-right: 0.25rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
// TODO: improve the look on breeze themes
|
|
||||||
background-color: $fallback--fg;
|
|
||||||
background-color: var(--btn, $fallback--fg);
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -20,7 +20,8 @@ const StatusPopover = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Status: () => import('../status/status.vue')
|
Status: () => import('../status/status.vue'),
|
||||||
|
Popover: () => import('../popover/popover.vue')
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
enter () {
|
enter () {
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<v-popover
|
<Popover trigger="hover">
|
||||||
popover-class="status-popover"
|
<template slot="trigger">
|
||||||
placement="top-start"
|
<slot />
|
||||||
:popper-options="popperOptions"
|
</template>
|
||||||
@show="enter()"
|
<div slot="content" class="status-popover">
|
||||||
>
|
|
||||||
<template slot="popover">
|
|
||||||
<Status
|
<Status
|
||||||
v-if="status"
|
v-if="status"
|
||||||
:is-preview="true"
|
:is-preview="true"
|
||||||
|
@ -18,10 +16,8 @@
|
||||||
>
|
>
|
||||||
<i class="icon-spin4 animate-spin" />
|
<i class="icon-spin4 animate-spin" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
|
</Popover>
|
||||||
<slot />
|
|
||||||
</v-popover>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./status_popover.js" ></script>
|
<script src="./status_popover.js" ></script>
|
||||||
|
@ -29,11 +25,11 @@
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '../../_variables.scss';
|
@import '../../_variables.scss';
|
||||||
|
|
||||||
.tooltip.popover.status-popover {
|
.status-popover {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
min-width: 15em;
|
min-width: 15em;
|
||||||
max-width: 95%;
|
max-width: 95%;
|
||||||
margin-left: 0.5em;
|
margin: 0.5em 0;
|
||||||
|
|
||||||
.popover-inner {
|
.popover-inner {
|
||||||
border-color: $fallback--border;
|
border-color: $fallback--border;
|
||||||
|
|
|
@ -19,6 +19,7 @@ import oauthTokensModule from './modules/oauth_tokens.js'
|
||||||
import reportsModule from './modules/reports.js'
|
import reportsModule from './modules/reports.js'
|
||||||
import pollsModule from './modules/polls.js'
|
import pollsModule from './modules/polls.js'
|
||||||
import postStatusModule from './modules/postStatus.js'
|
import postStatusModule from './modules/postStatus.js'
|
||||||
|
import popoverModule from './modules/popover.js'
|
||||||
|
|
||||||
import VueI18n from 'vue-i18n'
|
import VueI18n from 'vue-i18n'
|
||||||
|
|
||||||
|
@ -89,7 +90,8 @@ const persistedStateOptions = {
|
||||||
oauthTokens: oauthTokensModule,
|
oauthTokens: oauthTokensModule,
|
||||||
reports: reportsModule,
|
reports: reportsModule,
|
||||||
polls: pollsModule,
|
polls: pollsModule,
|
||||||
postStatus: postStatusModule
|
postStatus: postStatusModule,
|
||||||
|
popover: popoverModule
|
||||||
},
|
},
|
||||||
plugins: [persistedState, pushNotifications],
|
plugins: [persistedState, pushNotifications],
|
||||||
strict: false // Socket modifies itself, let's ignore this for now.
|
strict: false // Socket modifies itself, let's ignore this for now.
|
||||||
|
|
31
src/modules/popover.js
Normal file
31
src/modules/popover.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { omit } from 'lodash'
|
||||||
|
import { set } from 'vue'
|
||||||
|
|
||||||
|
const popover = {
|
||||||
|
state: {
|
||||||
|
popovers: {}
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
registerPopover (state, { id, el }) {
|
||||||
|
set(state.popovers, id, el)
|
||||||
|
},
|
||||||
|
unregisterPopover (state, { id }) {
|
||||||
|
state.popovers = omit(state.popovers, id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
registerPopover (store, el) {
|
||||||
|
// Generate unique id, it will be used to link portal and portal-target
|
||||||
|
// popover-target will make portal targets for each registered popover
|
||||||
|
// el will be used by popover target to put popovers in their places.
|
||||||
|
let id = Math.floor(Math.random() * 1000000).toString()
|
||||||
|
store.commit('registerPopover', { id, el })
|
||||||
|
return id
|
||||||
|
},
|
||||||
|
unregisterPopover (store, id) {
|
||||||
|
store.commit('unregisterPopover', { id })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default popover
|
Loading…
Reference in a new issue