forked from AkkomaGang/akkoma-fe
split status preview popover into a separate component
This commit is contained in:
parent
54a26be90c
commit
62b2648a3e
4 changed files with 136 additions and 100 deletions
|
@ -10,11 +10,12 @@ import Gallery from '../gallery/gallery.vue'
|
||||||
import LinkPreview from '../link-preview/link-preview.vue'
|
import LinkPreview from '../link-preview/link-preview.vue'
|
||||||
import AvatarList from '../avatar_list/avatar_list.vue'
|
import AvatarList from '../avatar_list/avatar_list.vue'
|
||||||
import Timeago from '../timeago/timeago.vue'
|
import Timeago from '../timeago/timeago.vue'
|
||||||
|
import StatusPopover from '../status_popover/status_popover.vue'
|
||||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||||
import fileType from 'src/services/file_type/file_type.service'
|
import fileType from 'src/services/file_type/file_type.service'
|
||||||
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
|
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
|
||||||
import { mentionMatchesUrl, extractTagFromUrl } from 'src/services/matcher/matcher.service.js'
|
import { mentionMatchesUrl, extractTagFromUrl } from 'src/services/matcher/matcher.service.js'
|
||||||
import { filter, find, unescape, uniqBy } from 'lodash'
|
import { filter, unescape, uniqBy } from 'lodash'
|
||||||
|
|
||||||
const Status = {
|
const Status = {
|
||||||
name: 'Status',
|
name: 'Status',
|
||||||
|
@ -37,7 +38,6 @@ const Status = {
|
||||||
replying: false,
|
replying: false,
|
||||||
unmuted: false,
|
unmuted: false,
|
||||||
userExpanded: false,
|
userExpanded: false,
|
||||||
preview: null,
|
|
||||||
showingTall: this.inConversation && this.focused,
|
showingTall: this.inConversation && this.focused,
|
||||||
showingLongSubject: false,
|
showingLongSubject: false,
|
||||||
error: null,
|
error: null,
|
||||||
|
@ -300,7 +300,8 @@ const Status = {
|
||||||
Gallery,
|
Gallery,
|
||||||
LinkPreview,
|
LinkPreview,
|
||||||
AvatarList,
|
AvatarList,
|
||||||
Timeago
|
Timeago,
|
||||||
|
StatusPopover
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
visibilityIcon (visibility) {
|
visibilityIcon (visibility) {
|
||||||
|
@ -375,24 +376,6 @@ const Status = {
|
||||||
this.expandingSubject = true
|
this.expandingSubject = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
replyEnter (id, event) {
|
|
||||||
const targetId = id
|
|
||||||
const statuses = this.$store.state.statuses.allStatuses
|
|
||||||
|
|
||||||
if (!this.preview) {
|
|
||||||
// if we have the status somewhere already
|
|
||||||
this.preview = find(statuses, { 'id': targetId })
|
|
||||||
// or if we have to fetch it
|
|
||||||
if (!this.preview) {
|
|
||||||
this.$store.state.api.backendInteractor.fetchStatus({ id }).then((status) => {
|
|
||||||
this.preview = status
|
|
||||||
this.$nextTick(this.$refs.statusPreviewPopper.updatePopper)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else if (this.preview.id !== targetId) {
|
|
||||||
this.preview = find(statuses, { 'id': targetId })
|
|
||||||
}
|
|
||||||
},
|
|
||||||
generateUserProfileLink (id, name) {
|
generateUserProfileLink (id, name) {
|
||||||
return generateProfileLink(id, name, this.$store.state.instance.restrictedNicknames)
|
return generateProfileLink(id, name, this.$store.state.instance.restrictedNicknames)
|
||||||
},
|
},
|
||||||
|
|
|
@ -174,33 +174,10 @@
|
||||||
v-if="isReply"
|
v-if="isReply"
|
||||||
class="reply-to-and-accountname"
|
class="reply-to-and-accountname"
|
||||||
>
|
>
|
||||||
<v-popover
|
<StatusPopover
|
||||||
v-if="!isPreview"
|
v-if="!isPreview"
|
||||||
ref="statusPreviewPopper"
|
:status-id="status.in_reply_to_status_id"
|
||||||
popover-class="status-popover"
|
|
||||||
placement="top-start"
|
|
||||||
:popper-options="{
|
|
||||||
modifiers: {
|
|
||||||
preventOverflow: { padding: { top: 50 }, boundariesElement: 'viewport' },
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
@show="replyEnter(status.in_reply_to_status_id)"
|
|
||||||
>
|
>
|
||||||
<div slot="popover">
|
|
||||||
<status
|
|
||||||
v-if="preview"
|
|
||||||
:is-preview="true"
|
|
||||||
:statusoid="preview"
|
|
||||||
:compact="true"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
v-else
|
|
||||||
class="status-preview-loading"
|
|
||||||
>
|
|
||||||
<i class="icon-spin4 animate-spin" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a
|
<a
|
||||||
class="reply-to"
|
class="reply-to"
|
||||||
href="#"
|
href="#"
|
||||||
|
@ -210,7 +187,7 @@
|
||||||
<i class="button-icon icon-reply" />
|
<i class="button-icon icon-reply" />
|
||||||
<span class="faint-link reply-to-text">{{ $t('status.reply_to') }}</span>
|
<span class="faint-link reply-to-text">{{ $t('status.reply_to') }}</span>
|
||||||
</a>
|
</a>
|
||||||
</v-popover>
|
</StatusPopover>
|
||||||
<span
|
<span
|
||||||
v-else
|
v-else
|
||||||
class="reply-to"
|
class="reply-to"
|
||||||
|
@ -863,59 +840,6 @@ a.unmute {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip.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);
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-el.status-el {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-preview-loading {
|
|
||||||
padding: 1em;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
i {
|
|
||||||
font-size: 2em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.favs-repeated-users {
|
.favs-repeated-users {
|
||||||
margin-top: $status-margin;
|
margin-top: $status-margin;
|
||||||
|
|
||||||
|
|
43
src/components/status_popover/status_popover.js
Normal file
43
src/components/status_popover/status_popover.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import { find } from 'lodash'
|
||||||
|
|
||||||
|
const StatusPopover = {
|
||||||
|
name: 'StatusPopover',
|
||||||
|
props: [
|
||||||
|
'statusId'
|
||||||
|
],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
preview: null,
|
||||||
|
popperOptions: {
|
||||||
|
modifiers: {
|
||||||
|
preventOverflow: { padding: { top: 50 }, boundariesElement: 'viewport' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Status: () => import('../status/status.vue')
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
enter () {
|
||||||
|
const id = this.statusId
|
||||||
|
const statuses = this.$store.state.statuses.allStatuses
|
||||||
|
|
||||||
|
if (!this.preview) {
|
||||||
|
// if we have the status somewhere already
|
||||||
|
this.preview = find(statuses, { id })
|
||||||
|
// or if we have to fetch it
|
||||||
|
if (!this.preview) {
|
||||||
|
this.$store.state.api.backendInteractor.fetchStatus({ id }).then((status) => {
|
||||||
|
this.preview = status
|
||||||
|
this.$nextTick(this.$refs.popper.updatePopper)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (this.preview.id !== id) {
|
||||||
|
this.preview = find(statuses, 'id')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StatusPopover
|
86
src/components/status_popover/status_popover.vue
Normal file
86
src/components/status_popover/status_popover.vue
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
<template>
|
||||||
|
<v-popover
|
||||||
|
ref="popper"
|
||||||
|
popover-class="status-popover"
|
||||||
|
placement="top-start"
|
||||||
|
:popper-options="popperOptions"
|
||||||
|
@show="enter()"
|
||||||
|
>
|
||||||
|
<div slot="popover">
|
||||||
|
<Status
|
||||||
|
v-if="preview"
|
||||||
|
:is-preview="true"
|
||||||
|
:statusoid="preview"
|
||||||
|
:compact="true"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="status-preview-loading"
|
||||||
|
>
|
||||||
|
<i class="icon-spin4 animate-spin" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<slot />
|
||||||
|
</v-popover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./status_popover.js" ></script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '../../_variables.scss';
|
||||||
|
|
||||||
|
.tooltip.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-el.status-el {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-preview-loading {
|
||||||
|
padding: 1em;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
Loading…
Reference in a new issue