Merge branch '599' into 'develop'

Fix "Posts get cut off when there is not enough space to display them at the bottom"

Closes #599

See merge request pleroma/pleroma-fe!863
This commit is contained in:
Shpuld Shpludson 2019-10-29 06:37:23 +00:00
commit c79da5c456
10 changed files with 185 additions and 143 deletions

View File

@ -39,10 +39,13 @@ h4 {
text-align: center; text-align: center;
} }
html {
font-size: 14px;
}
body { body {
font-family: sans-serif; font-family: sans-serif;
font-family: var(--interfaceFont, sans-serif); font-family: var(--interfaceFont, sans-serif);
font-size: 14px;
margin: 0; margin: 0;
color: $fallback--text; color: $fallback--text;
color: var(--text, $fallback--text); color: var(--text, $fallback--text);

View File

@ -4,8 +4,6 @@
trigger="click" trigger="click"
placement="top" placement="top"
class="extra-button-popover" class="extra-button-popover"
:offset="5"
:container="false"
> >
<div slot="popover"> <div slot="popover">
<div class="dropdown-menu"> <div class="dropdown-menu">

View File

@ -3,9 +3,7 @@
<v-popover <v-popover
trigger="click" trigger="click"
class="moderation-tools-popover" class="moderation-tools-popover"
:container="false"
placement="bottom-end" placement="bottom-end"
:offset="5"
@show="showDropDown = true" @show="showDropDown = true"
@hide="showDropDown = false" @hide="showDropDown = false"
> >

View File

@ -20,7 +20,6 @@
margin: 5px; margin: 5px;
border-color: $fallback--bg; border-color: $fallback--bg;
border-color: var(--bg, $fallback--bg); border-color: var(--bg, $fallback--bg);
z-index: 1;
} }
&[x-placement^="top"] { &[x-placement^="top"] {
@ -31,7 +30,7 @@
border-left-color: transparent !important; border-left-color: transparent !important;
border-right-color: transparent !important; border-right-color: transparent !important;
border-bottom-color: transparent !important; border-bottom-color: transparent !important;
bottom: -5px; bottom: -4px;
left: calc(50% - 5px); left: calc(50% - 5px);
margin-top: 0; margin-top: 0;
margin-bottom: 0; margin-bottom: 0;
@ -46,7 +45,7 @@
border-left-color: transparent !important; border-left-color: transparent !important;
border-right-color: transparent !important; border-right-color: transparent !important;
border-top-color: transparent !important; border-top-color: transparent !important;
top: -5px; top: -4px;
left: calc(50% - 5px); left: calc(50% - 5px);
margin-top: 0; margin-top: 0;
margin-bottom: 0; margin-bottom: 0;
@ -61,7 +60,7 @@
border-left-color: transparent !important; border-left-color: transparent !important;
border-top-color: transparent !important; border-top-color: transparent !important;
border-bottom-color: transparent !important; border-bottom-color: transparent !important;
left: -5px; left: -4px;
top: calc(50% - 5px); top: calc(50% - 5px);
margin-left: 0; margin-left: 0;
margin-right: 0; margin-right: 0;
@ -76,7 +75,7 @@
border-top-color: transparent !important; border-top-color: transparent !important;
border-right-color: transparent !important; border-right-color: transparent !important;
border-bottom-color: transparent !important; border-bottom-color: transparent !important;
right: -5px; right: -4px;
top: calc(50% - 5px); top: calc(50% - 5px);
margin-left: 0; margin-left: 0;
margin-right: 0; margin-right: 0;

View File

@ -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,8 +38,6 @@ const Status = {
replying: false, replying: false,
unmuted: false, unmuted: false,
userExpanded: false, userExpanded: false,
preview: null,
showPreview: false,
showingTall: this.inConversation && this.focused, showingTall: this.inConversation && this.focused,
showingLongSubject: false, showingLongSubject: false,
error: null, error: null,
@ -301,7 +300,8 @@ const Status = {
Gallery, Gallery,
LinkPreview, LinkPreview,
AvatarList, AvatarList,
Timeago Timeago,
StatusPopover
}, },
methods: { methods: {
visibilityIcon (visibility) { visibilityIcon (visibility) {
@ -376,27 +376,6 @@ const Status = {
this.expandingSubject = true this.expandingSubject = true
} }
}, },
replyEnter (id, event) {
this.showPreview = true
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
})
}
} else if (this.preview.id !== targetId) {
this.preview = find(statuses, { 'id': targetId })
}
},
replyLeave () {
this.showPreview = false
},
generateUserProfileLink (id, name) { generateUserProfileLink (id, name) {
return generateProfileLink(id, name, this.$store.state.instance.restrictedNicknames) return generateProfileLink(id, name, this.$store.state.instance.restrictedNicknames)
}, },

View File

@ -173,21 +173,27 @@
<div <div
v-if="isReply" v-if="isReply"
class="reply-to-and-accountname" class="reply-to-and-accountname"
>
<StatusPopover
v-if="!isPreview"
:status-id="status.in_reply_to_status_id"
> >
<a <a
class="reply-to" class="reply-to"
href="#" href="#"
:aria-label="$t('tool_tip.reply')" :aria-label="$t('tool_tip.reply')"
@click.prevent="gotoOriginal(status.in_reply_to_status_id)" @click.prevent="gotoOriginal(status.in_reply_to_status_id)"
@mouseenter.prevent.stop="replyEnter(status.in_reply_to_status_id, $event)"
@mouseleave.prevent.stop="replyLeave()"
> >
<i <i class="button-icon icon-reply" />
v-if="!isPreview"
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>
</StatusPopover>
<span
v-else
class="reply-to"
>
<span class="reply-to-text">{{ $t('status.reply_to') }}</span>
</span>
<router-link :to="replyProfileLink"> <router-link :to="replyProfileLink">
{{ replyToName }} {{ replyToName }}
</router-link> </router-link>
@ -199,50 +205,25 @@
</span> </span>
</div> </div>
<div <div
v-if="inConversation && !isPreview" v-if="inConversation && !isPreview && replies && replies.length"
class="replies" class="replies"
> >
<span <span class="faint">{{ $t('status.replies_list') }}</span>
v-if="replies && replies.length" <StatusPopover
class="faint"
>{{ $t('status.replies_list') }}</span>
<template v-if="replies">
<span
v-for="reply in replies" v-for="reply in replies"
:key="reply.id" :key="reply.id"
class="reply-link faint" :status-id="reply.id"
> >
<a <a
href="#" href="#"
class="reply-link"
@click.prevent="gotoOriginal(reply.id)" @click.prevent="gotoOriginal(reply.id)"
@mouseenter="replyEnter(reply.id, $event)"
@mouseout="replyLeave()"
>{{ reply.name }}</a> >{{ reply.name }}</a>
</span> </StatusPopover>
</template>
</div> </div>
</div> </div>
</div> </div>
<div
v-if="showPreview"
class="status-preview-container"
>
<status
v-if="preview"
class="status-preview"
:is-preview="true"
:statusoid="preview"
:compact="true"
/>
<div
v-else
class="status-preview status-preview-loading"
>
<i class="icon-spin4 animate-spin" />
</div>
</div>
<div <div
v-if="longSubject" v-if="longSubject"
class="status-content-wrapper" class="status-content-wrapper"
@ -439,18 +420,6 @@ $status-margin: 0.75em;
min-width: 0; min-width: 0;
} }
.status-preview.status-el {
border-style: solid;
border-width: 1px;
border-color: $fallback--border;
border-color: var(--border, $fallback--border);
}
.status-preview-container {
position: relative;
max-width: 100%;
}
.status-pin { .status-pin {
padding: $status-margin $status-margin 0; padding: $status-margin $status-margin 0;
display: flex; display: flex;
@ -458,44 +427,6 @@ $status-margin: 0.75em;
justify-content: flex-end; justify-content: flex-end;
} }
.status-preview {
position: absolute;
max-width: 95%;
display: flex;
background-color: $fallback--bg;
background-color: var(--bg, $fallback--bg);
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);
margin-top: 0.25em;
margin-left: 0.5em;
z-index: 50;
.status {
flex: 1;
border: 0;
min-width: 15em;
}
}
.status-preview-loading {
display: block;
min-width: 15em;
padding: 1em;
text-align: center;
border-width: 1px;
border-style: solid;
i {
font-size: 2em;
}
}
.media-left { .media-left {
margin-right: $status-margin; margin-right: $status-margin;
} }
@ -553,11 +484,6 @@ $status-margin: 0.75em;
flex-basis: 100%; flex-basis: 100%;
margin-bottom: 0.5em; margin-bottom: 0.5em;
a {
display: inline-block;
word-break: break-all;
}
small { small {
font-weight: lighter; font-weight: lighter;
} }
@ -568,6 +494,11 @@ $status-margin: 0.75em;
justify-content: space-between; justify-content: space-between;
line-height: 18px; line-height: 18px;
a {
display: inline-block;
word-break: break-all;
}
.name-and-account-name { .name-and-account-name {
display: flex; display: flex;
min-width: 0; min-width: 0;
@ -600,6 +531,7 @@ $status-margin: 0.75em;
} }
.heading-reply-row { .heading-reply-row {
position: relative;
align-content: baseline; align-content: baseline;
font-size: 12px; font-size: 12px;
line-height: 18px; line-height: 18px;
@ -608,11 +540,13 @@ $status-margin: 0.75em;
flex-wrap: wrap; flex-wrap: wrap;
align-items: stretch; align-items: stretch;
a { > .reply-to-and-accountname > a {
max-width: 100%; max-width: 100%;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
display: inline-block;
word-break: break-all;
} }
} }
@ -639,6 +573,8 @@ $status-margin: 0.75em;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
margin: 0 0.4em 0 0.2em; margin: 0 0.4em 0 0.2em;
color: $fallback--faint;
color: var(--faint, $fallback--faint);
} }
.replies-separator { .replies-separator {

View File

@ -0,0 +1,34 @@
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')
},
methods: {
enter () {
if (!this.status) {
this.$store.dispatch('fetchStatus', this.statusId)
}
}
}
}
export default StatusPopover

View File

@ -0,0 +1,85 @@
<template>
<v-popover
popover-class="status-popover"
placement="top-start"
:popper-options="popperOptions"
@show="enter()"
>
<template slot="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>
</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>

View File

@ -41,7 +41,13 @@ Vue.use(VueChatScroll)
Vue.use(VueClickOutside) Vue.use(VueClickOutside)
Vue.use(PortalVue) Vue.use(PortalVue)
Vue.use(VBodyScrollLock) Vue.use(VBodyScrollLock)
Vue.use(VTooltip) Vue.use(VTooltip, {
popover: {
defaultTrigger: 'hover click',
defaultContainer: false,
defaultOffset: 5
}
})
const i18n = new VueI18n({ const i18n = new VueI18n({
// By default, use the browser locale, we will update it if neccessary // By default, use the browser locale, we will update it if neccessary

View File

@ -537,6 +537,10 @@ const statuses = {
setNotificationsSilence ({ rootState, commit }, { value }) { setNotificationsSilence ({ rootState, commit }, { value }) {
commit('setNotificationsSilence', { value }) commit('setNotificationsSilence', { value })
}, },
fetchStatus ({ rootState, dispatch }, id) {
rootState.api.backendInteractor.fetchStatus({ id })
.then((status) => dispatch('addNewStatuses', { statuses: [status] }))
},
deleteStatus ({ rootState, commit }, status) { deleteStatus ({ rootState, commit }, status) {
commit('setDeleted', { status }) commit('setDeleted', { status })
apiService.deleteStatus({ id: status.id, credentials: rootState.users.currentUser.credentials }) apiService.deleteStatus({ id: status.id, credentials: rootState.users.currentUser.credentials })