Page MenuHomePhorge

No OneTemporary

Authored By
Unknown
Size
33 KB
Referenced Files
None
Subscribers
None
diff --git a/src/App.js b/src/App.js
index 61b5eec1c6..041e131a57 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,123 +1,125 @@
import UserPanel from './components/user_panel/user_panel.vue'
import NavPanel from './components/nav_panel/nav_panel.vue'
import Notifications from './components/notifications/notifications.vue'
import SearchBar from './components/search_bar/search_bar.vue'
import InstanceSpecificPanel from './components/instance_specific_panel/instance_specific_panel.vue'
import FeaturesPanel from './components/features_panel/features_panel.vue'
import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_panel.vue'
import ChatPanel from './components/chat_panel/chat_panel.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'
import MobileNav from './components/mobile_nav/mobile_nav.vue'
import UserReportingModal from './components/user_reporting_modal/user_reporting_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'
export default {
name: 'app',
components: {
UserPanel,
NavPanel,
Notifications,
SearchBar,
InstanceSpecificPanel,
FeaturesPanel,
WhoToFollowPanel,
ChatPanel,
MediaModal,
SideDrawer,
MobilePostStatusButton,
MobileNav,
UserReportingModal,
- PostStatusModal
+ PostStatusModal,
+ PopoverTarget
},
data: () => ({
mobileActivePanel: 'timeline',
searchBarHidden: true,
supportsMask: window.CSS && window.CSS.supports && (
window.CSS.supports('mask-size', 'contain') ||
window.CSS.supports('-webkit-mask-size', 'contain') ||
window.CSS.supports('-moz-mask-size', 'contain') ||
window.CSS.supports('-ms-mask-size', 'contain') ||
window.CSS.supports('-o-mask-size', 'contain')
)
}),
created () {
// Load the locale from the storage
this.$i18n.locale = this.$store.getters.mergedConfig.interfaceLanguage
window.addEventListener('resize', this.updateMobileState)
},
destroyed () {
window.removeEventListener('resize', this.updateMobileState)
},
computed: {
currentUser () { return this.$store.state.users.currentUser },
background () {
return this.currentUser.background_image || this.$store.state.instance.background
},
enableMask () { return this.supportsMask && this.$store.state.instance.logoMask },
logoStyle () {
return {
'visibility': this.enableMask ? 'hidden' : 'visible'
}
},
logoMaskStyle () {
return this.enableMask ? {
'mask-image': `url(${this.$store.state.instance.logo})`
} : {
'background-color': this.enableMask ? '' : 'transparent'
}
},
logoBgStyle () {
return Object.assign({
'margin': `${this.$store.state.instance.logoMargin} 0`,
opacity: this.searchBarHidden ? 1 : 0
}, this.enableMask ? {} : {
'background-color': this.enableMask ? '' : 'transparent'
})
},
logo () { return this.$store.state.instance.logo },
bgStyle () {
return {
'background-image': `url(${this.background})`
}
},
bgAppStyle () {
return {
'--body-background-image': `url(${this.background})`
}
},
sitename () { return this.$store.state.instance.name },
chat () { return this.$store.state.chat.channel.state === 'joined' },
hideSitename () { return this.$store.state.instance.hideSitename },
suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled },
showInstanceSpecificPanel () {
return this.$store.state.instance.showInstanceSpecificPanel &&
!this.$store.getters.mergedConfig.hideISP &&
this.$store.state.instance.instanceSpecificPanelContent
},
showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel },
isMobileLayout () { return this.$store.state.interface.mobileLayout },
privateMode () { return this.$store.state.instance.private }
},
methods: {
scrollToTop () {
window.scrollTo(0, 0)
},
logout () {
this.$router.replace('/main/public')
this.$store.dispatch('logout')
},
onSearchBarToggled (hidden) {
this.searchBarHidden = hidden
},
updateMobileState () {
const mobileLayout = windowWidth() <= 800
const changed = mobileLayout !== this.isMobileLayout
if (changed) {
this.$store.dispatch('setMobileLayout', mobileLayout)
}
}
}
}
diff --git a/src/App.vue b/src/App.vue
index 1b1c2648ca..de15802fa8 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,130 +1,131 @@
<template>
<div
id="app"
:style="bgAppStyle"
>
<div
id="app_bg_wrapper"
class="app-bg-wrapper"
:style="bgStyle"
/>
<MobileNav v-if="isMobileLayout" />
<nav
v-else
id="nav"
class="nav-bar container"
@click="scrollToTop()"
>
<div class="inner-nav">
<div
class="logo"
:style="logoBgStyle"
>
<div
class="mask"
:style="logoMaskStyle"
/>
<img
:src="logo"
:style="logoStyle"
>
</div>
<div class="item">
<router-link
v-if="!hideSitename"
class="site-name"
:to="{ name: 'root' }"
active-class="home"
>
{{ sitename }}
</router-link>
</div>
<div class="item right">
<search-bar
v-if="currentUser || !privateMode"
class="nav-icon mobile-hidden"
@toggled="onSearchBarToggled"
@click.stop.native
/>
<router-link
class="mobile-hidden"
:to="{ name: 'settings'}"
>
<i
class="button-icon icon-cog nav-icon"
:title="$t('nav.preferences')"
/>
</router-link>
<a
v-if="currentUser && currentUser.role === 'admin'"
href="/pleroma/admin/#/login-pleroma"
class="mobile-hidden"
target="_blank"
><i
class="button-icon icon-gauge nav-icon"
:title="$t('nav.administration')"
/></a>
<a
v-if="currentUser"
href="#"
class="mobile-hidden"
@click.prevent="logout"
><i
class="button-icon icon-logout nav-icon"
:title="$t('login.logout')"
/></a>
</div>
</div>
</nav>
<div
id="content"
class="container"
>
<div class="sidebar-flexer mobile-hidden">
<div class="sidebar-bounds">
<div class="sidebar-scroller">
<div class="sidebar">
<user-panel />
<div v-if="!isMobileLayout">
<nav-panel />
<instance-specific-panel v-if="showInstanceSpecificPanel" />
<features-panel v-if="!currentUser && showFeaturesPanel" />
<who-to-follow-panel v-if="currentUser && suggestionsEnabled" />
<notifications v-if="currentUser" />
</div>
</div>
</div>
</div>
</div>
<div class="main">
<div
v-if="!currentUser"
class="login-hint panel panel-default"
>
<router-link
:to="{ name: 'login' }"
class="panel-body"
>
{{ $t("login.hint") }}
</router-link>
</div>
<transition name="fade">
<router-view />
</transition>
</div>
<media-modal />
</div>
<chat-panel
v-if="currentUser && chat"
:floating="true"
class="floating-chat mobile-hidden"
/>
<MobilePostStatusButton />
<UserReportingModal />
<PostStatusModal />
<portal-target name="modal" />
+ <PopoverTarget />
</div>
</template>
<script src="./App.js"></script>
<style lang="scss" src="./App.scss"></style>
diff --git a/src/components/extra_buttons/extra_buttons.js b/src/components/extra_buttons/extra_buttons.js
index 5ac73e975a..3748538322 100644
--- a/src/components/extra_buttons/extra_buttons.js
+++ b/src/components/extra_buttons/extra_buttons.js
@@ -1,50 +1,53 @@
+import Popover from '../popover/popover.vue'
+
const ExtraButtons = {
props: [ 'status' ],
+ components: { Popover },
methods: {
deleteStatus () {
const confirmed = window.confirm(this.$t('status.delete_confirm'))
if (confirmed) {
this.$store.dispatch('deleteStatus', { id: this.status.id })
}
},
pinStatus () {
this.$store.dispatch('pinStatus', this.status.id)
.then(() => this.$emit('onSuccess'))
.catch(err => this.$emit('onError', err.error.error))
},
unpinStatus () {
this.$store.dispatch('unpinStatus', this.status.id)
.then(() => this.$emit('onSuccess'))
.catch(err => this.$emit('onError', err.error.error))
},
muteConversation () {
this.$store.dispatch('muteConversation', this.status.id)
.then(() => this.$emit('onSuccess'))
.catch(err => this.$emit('onError', err.error.error))
},
unmuteConversation () {
this.$store.dispatch('unmuteConversation', this.status.id)
.then(() => this.$emit('onSuccess'))
.catch(err => this.$emit('onError', err.error.error))
}
},
computed: {
currentUser () { return this.$store.state.users.currentUser },
canDelete () {
if (!this.currentUser) { return }
const superuser = this.currentUser.rights.moderator || this.currentUser.rights.admin
return superuser || this.status.user.id === this.currentUser.id
},
ownStatus () {
return this.status.user.id === this.currentUser.id
},
canPin () {
return this.ownStatus && (this.status.visibility === 'public' || this.status.visibility === 'unlisted')
},
canMute () {
return !!this.currentUser
}
}
}
export default ExtraButtons
diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue
index 746f1c9175..3f00342528 100644
--- a/src/components/extra_buttons/extra_buttons.vue
+++ b/src/components/extra_buttons/extra_buttons.vue
@@ -1,71 +1,75 @@
<template>
- <v-popover
+ <Popover
v-if="canDelete || canMute || canPin"
trigger="click"
- placement="top"
+ placement="bottom"
class="extra-button-popover"
>
- <div slot="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 class="button-icon">
+ <div slot="trigger" class="button-icon">
<i class="icon-ellipsis" />
</div>
- </v-popover>
+ </Popover>
</template>
<script src="./extra_buttons.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
@import '../popper/popper.scss';
+.dropdown-menu {
+ flex-shrink: 0;
+}
+
.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
new file mode 100644
index 0000000000..4ee083232f
--- /dev/null
+++ b/src/components/popover/popover.js
@@ -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
diff --git a/src/components/popper/popper.scss b/src/components/popover/popover.vue
similarity index 76%
copy from src/components/popper/popper.scss
copy to src/components/popover/popover.vue
index 06daa8714a..273a0a69fe 100644
--- a/src/components/popper/popper.scss
+++ b/src/components/popover/popover.vue
@@ -1,147 +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';
-.tooltip.popover {
+.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: normal;
+ 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>
diff --git a/src/components/popover/popover_target.js b/src/components/popover/popover_target.js
new file mode 100644
index 0000000000..60bed5c792
--- /dev/null
+++ b/src/components/popover/popover_target.js
@@ -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
diff --git a/src/components/popover/popover_target.vue b/src/components/popover/popover_target.vue
new file mode 100644
index 0000000000..f012823c33
--- /dev/null
+++ b/src/components/popover/popover_target.vue
@@ -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>
diff --git a/src/components/popper/popper.scss b/src/components/popper/popper.scss
index 06daa8714a..e69de29bb2 100644
--- a/src/components/popper/popper.scss
+++ b/src/components/popper/popper.scss
@@ -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;
- }
- }
-}
diff --git a/src/components/status_popover/status_popover.js b/src/components/status_popover/status_popover.js
index 19f16bd980..4055e5cb48 100644
--- a/src/components/status_popover/status_popover.js
+++ b/src/components/status_popover/status_popover.js
@@ -1,34 +1,35 @@
import { find } from 'lodash'
const StatusPopover = {
name: '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 () {
if (!this.status) {
this.$store.dispatch('fetchStatus', this.statusId)
}
}
}
}
export default StatusPopover
diff --git a/src/components/status_popover/status_popover.vue b/src/components/status_popover/status_popover.vue
index eacf4c0675..9f37e4e7a1 100644
--- a/src/components/status_popover/status_popover.vue
+++ b/src/components/status_popover/status_popover.vue
@@ -1,85 +1,81 @@
<template>
- <v-popover
- popover-class="status-popover"
- placement="top-start"
- :popper-options="popperOptions"
- @show="enter()"
- >
- <template slot="popover">
+ <Popover trigger="hover">
+ <template slot="trigger">
+ <slot />
+ </template>
+ <div slot="content" class="status-popover">
<Status
v-if="status"
:is-preview="true"
:statusoid="status"
:compact="true"
/>
<div
v-else
class="status-preview-loading"
>
<i class="icon-spin4 animate-spin" />
</div>
- </template>
-
- <slot />
- </v-popover>
+ </div>
+ </Popover>
</template>
<script src="./status_popover.js" ></script>
<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;
+ margin: 0.5em 0;
.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);
}
.status-el.status-el {
border: none;
}
.status-preview-loading {
padding: 1em;
text-align: center;
i {
font-size: 2em;
}
}
}
</style>
diff --git a/src/main.js b/src/main.js
index baf73ac8b5..d74ff63ad7 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,106 +1,108 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import Vuex from 'vuex'
import 'custom-event-polyfill'
import './lib/event_target_polyfill.js'
import interfaceModule from './modules/interface.js'
import instanceModule from './modules/instance.js'
import statusesModule from './modules/statuses.js'
import usersModule from './modules/users.js'
import apiModule from './modules/api.js'
import configModule from './modules/config.js'
import chatModule from './modules/chat.js'
import oauthModule from './modules/oauth.js'
import authFlowModule from './modules/auth_flow.js'
import mediaViewerModule from './modules/media_viewer.js'
import oauthTokensModule from './modules/oauth_tokens.js'
import reportsModule from './modules/reports.js'
import pollsModule from './modules/polls.js'
import postStatusModule from './modules/postStatus.js'
+import popoverModule from './modules/popover.js'
import VueI18n from 'vue-i18n'
import createPersistedState from './lib/persisted_state.js'
import pushNotifications from './lib/push_notifications_plugin.js'
import messages from './i18n/messages.js'
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'
const currentLocale = (window.navigator.language || 'en').split('-')[0]
Vue.use(Vuex)
Vue.use(VueRouter)
Vue.use(VueI18n)
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
locale: currentLocale,
fallbackLocale: 'en',
messages
})
const persistedStateOptions = {
paths: [
'config',
'users.lastLoginName',
'oauth'
]
};
(async () => {
const persistedState = await createPersistedState(persistedStateOptions)
const store = new Vuex.Store({
modules: {
i18n: {
getters: {
i18n: () => i18n
}
},
interface: interfaceModule,
instance: instanceModule,
statuses: statusesModule,
users: usersModule,
api: apiModule,
config: configModule,
chat: chatModule,
oauth: oauthModule,
authFlow: authFlowModule,
mediaViewer: mediaViewerModule,
oauthTokens: oauthTokensModule,
reports: reportsModule,
polls: pollsModule,
- postStatus: postStatusModule
+ postStatus: postStatusModule,
+ popover: popoverModule
},
plugins: [persistedState, pushNotifications],
strict: false // Socket modifies itself, let's ignore this for now.
// strict: process.env.NODE_ENV !== 'production'
})
afterStoreSetup({ store, i18n })
})()
// These are inlined by webpack's DefinePlugin
/* eslint-disable */
window.___pleromafe_mode = process.env
window.___pleromafe_commit_hash = COMMIT_HASH
window.___pleromafe_dev_overrides = DEV_OVERRIDES
diff --git a/src/modules/popover.js b/src/modules/popover.js
new file mode 100644
index 0000000000..5b01ccbb45
--- /dev/null
+++ b/src/modules/popover.js
@@ -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

File Metadata

Mime Type
text/x-diff
Expires
Sun, Nov 1, 5:11 AM (13 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1802509
Default Alt Text
(33 KB)

Event Timeline