Merge pull request #1744 from nextcloud/artonge/fix/fixes

Front-end fixes
pull/1745/head
Louis 2023-04-20 20:03:40 +02:00 zatwierdzone przez GitHub
commit 281373117b
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
12 zmienionych plików z 126 dodań i 126 usunięć

Wyświetl plik

@ -68,7 +68,7 @@
:contenteditable="!loading"
class="message"
placeholder="What would you like to share?"
:class="{'icon-loading': loading}"
:class="{'icon-loading': loading, 'too-long': statusIsTooLong}"
@keyup.prevent.enter="keyup"
@input="updateStatusContent"
@tribute-replaced="updatePostFromTribute" />
@ -277,12 +277,24 @@ export default {
return true
}
return !this.statusIsEmpty
if (this.statusIsTooLong) {
return false
}
if (this.statusIsEmpty) {
return false
}
return true
},
/** @return {boolean} */
statusIsEmpty() {
return this.statusContent.length === 0 || this.statusContent === '<br>'
},
statusIsTooLong() {
return this.statusContent.length > 500
},
},
mounted() {
this.$root.$on('composer-reply', (/** @type {import('../../types/Mastodon.js').Status} */data) => {
@ -518,6 +530,10 @@ export default {
min-width: 2px;
display: block;
&.too-long {
color: var(--color-error);
}
:deep(.mention) {
color: var(--color-primary-element);
background-color: var(--color-background-dark);

Wyświetl plik

@ -65,7 +65,7 @@ export default {
case 'followers':
return t('social', 'Post to followers')
case 'direct':
return t('social', 'Post to mentioned users')
return t('social', 'Send message to mentioned users')
}
return ''
},

Wyświetl plik

@ -72,10 +72,6 @@ export default {
currentUser,
],
props: {
account: {
type: String,
default: '',
},
uid: {
type: String,
default: '',

Wyświetl plik

@ -59,7 +59,7 @@
<!-- Hack to render note safely -->
<MessageContent v-if="accountInfo.note" class="user-profile__note user-profile__info" :item="{content: accountInfo.note, tag: [], mentions: []}" />
<FollowButton class="user-profile__info" :account="accountInfo.acct" :uid="uid" />
<FollowButton class="user-profile__info" :uid="uid" />
<NcButton v-if="serverData.public"
class="user-profile__info primary"
@click="followRemote">

Wyświetl plik

@ -48,9 +48,5 @@ export default {
padding: 5px 10px 10px 5px;
height: 52px;
width: 52px;
.avatardiv {
position: static;
}
}
</style>

Wyświetl plik

@ -5,39 +5,49 @@
<img :src="notification.account.avatar">
<Heart v-if="notification.type === 'favourite'" :size="16" />
<Repeat v-if="notification.type === 'reblog'" :size="16" />
<AccountPlusOutline v-if="notification.type === 'follow'" :size="16" />
<AccountQuestion v-if="notification.type === 'follow_request'" :size="16" />
<At v-if="notification.type === 'mention'" :size="16" />
<MessageOutline v-if="notification.type === 'status'" :size="16" />
<MessagePlusOutline v-if="notification.type === 'update'" :size="16" />
<Poll v-if="notification.type === 'poll'" :size="16" />
{{ actionSummary }}
</span>
<span class="notification__details">
<router-link :to="{ name: 'single-post', params: {
<router-link v-if="!notificationIsAboutAnAccount"
:to="{ name: 'single-post', params: {
account: item.account.display_name,
id: notification.status.id,
type: 'single-post',
} }"
:data-timestamp="notification.created_at"
class="post-timestamp live-relative-timestamp"
class="post-timestamp"
:title="notificationFormattedDate">
{{ notificationRelativeTimestamp }}
</router-link>
<span v-else
class="post-timestamp"
:data-timestamp="notification.created_at"
:title="notificationFormattedDate">
{{ notificationRelativeTimestamp }}
</span>
</span>
</div>
<template v-else-if="isBoost">
<div class="container-icon-boost boost">
<span class="icon-boost" />
</div>
<div class="boost">
<Repeat :size="16" />
<router-link :to="{ name: 'profile', params: { account: item.account.acct } }">
<img :src="item.account.avatar">
<span :title="item.account.acct" class="post-author">
{{ item.account.display_name }}
{{ item.account.display_name }}&ensp;
</span>
</router-link>
{{ t('social', 'boosted') }}
</div>
</template>
<UserEntry v-if="isNotification && notificationIsAboutAnAccount"
:key="item.account.id"
:item="item.account" />
<UserEntry v-if="isNotification && notificationIsAboutAnAccount" :item="item.account" />
<template v-else>
<div class="wrapper">
<div v-if="entryContent" class="wrapper">
<TimelineAvatar v-if="!isNotification" class="entry__avatar" :item="entryContent" />
<TimelinePost class="entry__content"
:item="entryContent"
@ -50,8 +60,13 @@
<script>
import Bell from 'vue-material-design-icons/Bell.vue'
import Repeat from 'vue-material-design-icons/Repeat.vue'
import Reply from 'vue-material-design-icons/Reply.vue'
import Heart from 'vue-material-design-icons/Heart.vue'
import AccountPlusOutline from 'vue-material-design-icons/AccountPlusOutline.vue'
import AccountQuestion from 'vue-material-design-icons/AccountQuestion.vue'
import At from 'vue-material-design-icons/At.vue'
import Poll from 'vue-material-design-icons/Poll.vue'
import MessageOutline from 'vue-material-design-icons/MessageOutline.vue'
import MessagePlusOutline from 'vue-material-design-icons/MessagePlusOutline.vue'
import { translate } from '@nextcloud/l10n'
import moment from '@nextcloud/moment'
import TimelinePost from './TimelinePost.vue'
@ -67,8 +82,13 @@ export default {
UserEntry,
Bell,
Repeat,
Reply,
Heart,
AccountPlusOutline,
AccountQuestion,
At,
Poll,
MessageOutline,
MessagePlusOutline,
},
props: {
/** @type {import('vue').PropType<import('../types/Mastodon.js').Status|import('../types/Mastodon.js').Notification>} */
@ -93,7 +113,8 @@ export default {
if (this.isNotification) {
return this.notification.status
} else if (this.isBoost) {
return this.status.reblog
// We use the object stored in the store so that actions on it are reflected.
return this.$store.getters.getStatus(this.item.reblog.id)
} else {
return this.item
}
@ -124,7 +145,7 @@ export default {
},
/** @return {boolean} */
notificationIsAboutAnAccount() {
return this.notification.type in ['follow', 'follow_request', 'admin.sign_up', 'admin.report']
return ['follow', 'follow_request', 'admin.sign_up', 'admin.report'].includes(this.notification.type)
},
/**
* @return {boolean}
@ -191,7 +212,6 @@ export default {
width: 32px;
border-radius: 50%;
overflow: hidden;
margin-right: 3px;
vertical-align: middle;
margin-top: -1px;
margin-right: 8px;
@ -206,12 +226,12 @@ export default {
border-radius: 50%;
border: 1px solid var(--color-background-dark);
}
}
&__details a {
&__details .post-timestamp {
color: var(--color-text-lighter);
}
&__details a {
&:hover {
text-decoration: underline;
}
@ -226,38 +246,25 @@ export default {
display: none;
}
}
}
.icon-boost {
display: inline-block;
vertical-align: middle;
}
.icon-favorite {
display: inline-block;
vertical-align: middle;
}
.icon-user {
display: inline-block;
vertical-align: middle;
}
.container-icon-boost {
display: inline-block;
padding-right: 6px;
}
.icon-boost {
display: inline-block;
width: 38px;
height: 17px;
opacity: .5;
background-position: right center;
vertical-align: middle;
:deep(.user-entry) {
.user-avatar {
display: none;
}
}
}
.boost {
opacity: .5;
color: var(--color-text-lighter);
display: flex;
margin-left: 21px; // To align with status' text.
img {
width: 16px;
border-radius: 50%;
vertical-align: middle;
margin-top: -4px;
margin-left: 4px;
}
}
</style>

Wyświetl plik

@ -38,10 +38,8 @@
<template #icon>
<Reply :size="20" />
</template>
<template #default>
<span v-if="item.replies_count !== 0">
{{ item.replies_count }}
</span>
<template>
{{ item.replies_count > 0 ? item.replies_count : '' }}
</template>
</NcButton>
<NcButton v-if="item.visibility === 'public' || item.visibility === 'unlisted'"
@ -51,10 +49,8 @@
<template #icon>
<Repeat :size="20" :fill-color="isBoosted ? 'var(--color-primary)' : 'var(--color-main-text)'" />
</template>
<template #default>
<span v-if="item.reblogs_count !== 0">
{{ item.reblogs_count }}
</span>
<template>
{{ item.reblogs_count > 0 ? item.reblogs_count : '' }}
</template>
</NcButton>
<NcButton v-if="!isLiked"
@ -64,10 +60,8 @@
<template #icon>
<HeartOutline :size="20" />
</template>
<template #default>
<span v-if="item.favourites_count !== 0">
{{ item.favourites_count }}
</span>
<template>
{{ item.favourites_count > 0 ? item.favourites_count : '' }}
</template>
</NcButton>
<NcButton v-if="isLiked"
@ -77,6 +71,9 @@
<template #icon>
<Heart :size="20" :fill-color="'var(--color-error)'" />
</template>
<template>
{{ item.favourites_count > 0 ? item.favourites_count : '' }}
</template>
</NcButton>
<NcActions>
<NcActionButton v-if="item.account.acct === currentAccount?.acct"
@ -327,33 +324,8 @@ export default {
margin: 4px;
.button-vue:hover {
// Else hover state is the same as the background.
background: var(--color-background-dark);
}
.post-actions-more {
position: relative;
width: 44px;
height: 34px;
display: inline-block;
}
.icon-reply,
.icon-boost,
.icon-boosted,
.icon-starred,
.icon-favorite,
.icon-more {
display: inline-block;
width: 44px;
height: 34px;
opacity: .5;
&:hover, &:focus {
opacity: 1;
}
}
.icon-boosted {
opacity: 1;
}
}
</style>

Wyświetl plik

@ -53,7 +53,7 @@
<!-- eslint-disable-next-line vue/no-v-html -->
<p v-html="item.note" />
</div>
<FollowButton :account="item.acct" :uid="cloudId" />
<FollowButton :uid="item.acct" />
</div>
</div>
</template>
@ -92,6 +92,11 @@ export default {
return !this.item.acct.includes('@')
},
},
async mounted() {
if (this.relationship === undefined) {
await this.$store.dispatch('fetchAccountRelationshipInfo', [this.item.id])
}
},
}
</script>
<style scoped lang="scss">

Wyświetl plik

@ -26,7 +26,7 @@ export default [
},
{
id: 'direct',
text: t('social', 'Direct'),
text: t('social', 'Direct message'),
description: t('social', 'Visible to mentioned users only'),
},
]

Wyświetl plik

@ -201,7 +201,7 @@ const actions = {
commit('setCurrentAccount', account)
dispatch('fetchAccountInfo', account)
},
async followAccount(context, { currentAccount, accountToFollow }) {
async followAccount(context, { accountToFollow }) {
try {
const response = await axios.put(generateUrl('/apps/social/api/v1/current/follow?account=' + accountToFollow))
if (response.data.status === -1) {
@ -214,7 +214,7 @@ const actions = {
logger.error(`Failed to follow user ${accountToFollow}`, { error })
}
},
async unfollowAccount(context, { currentAccount, accountToUnfollow }) {
async unfollowAccount(context, { accountToUnfollow }) {
try {
const response = await axios.delete(generateUrl('/apps/social/api/v1/current/follow?account=' + accountToUnfollow))
if (response.data.status === -1) {

Wyświetl plik

@ -69,6 +69,18 @@ const state = {
composerDisplayStatus: false,
}
/**
*
* @param {typeof state} state
* @param {import ('../types/Mastodon.js').Status} status
*/
function addToStatuses(state, status) {
Vue.set(state.statuses, status.id, status)
if (status.reblog !== undefined && status.reblog !== null) {
Vue.set(state.statuses, status.reblog.id, status.reblog)
}
}
/** @type {import('vuex').MutationTree<state>} */
const mutations = {
/**
@ -76,7 +88,7 @@ const mutations = {
* @param {import ('../types/Mastodon.js').Status} status
*/
addToStatuses(state, status) {
Vue.set(state.statuses, status.id, status)
addToStatuses(state, status)
},
/**
* @param state
@ -84,13 +96,13 @@ const mutations = {
*/
addToTimeline(state, data) {
if (Array.isArray(data)) {
data.forEach(status => Vue.set(state.statuses, status.id, status))
data.forEach(status => addToStatuses(state, status))
data
.filter(status => state.timeline.indexOf(status.id) === -1)
.forEach(status => state.timeline.push(status.id))
} else {
data.descendants.forEach(status => Vue.set(state.statuses, status.id, status))
data.ancestors.forEach(status => Vue.set(state.statuses, status.id, status))
data.descendants.forEach(status => addToStatuses(state, status))
data.ancestors.forEach(status => addToStatuses(state, status))
data.descendants
.filter(status => state.timeline.indexOf(status.id) === -1)
@ -100,22 +112,11 @@ const mutations = {
.forEach(status => state.parentsTimeline.push(status.id))
}
},
/**
* @param state
* @param {import ('../types/Mastodon.js').Status[]} data
*/
updateInTimelines(state, data) {
data.forEach((status) => {
if (state.statuses[status.id] !== undefined) {
Vue.set(state.statuses, status.id, status)
}
})
},
/**
* @param state
* @param {import('../types/Mastodon.js').Status} status
*/
removeStatusf(state, status) {
removeStatus(state, status) {
const timelineIndex = state.timeline.indexOf(status.id)
if (timelineIndex !== -1) {
state.timeline.splice(timelineIndex, 1)
@ -161,6 +162,7 @@ const mutations = {
likeStatus(state, { status }) {
if (state.statuses[status.id] !== undefined) {
Vue.set(state.statuses[status.id], 'favourited', true)
state.statuses[status.id].favourites_count++
}
},
/**
@ -171,6 +173,7 @@ const mutations = {
unlikeStatus(state, { status }) {
if (state.statuses[status.id] !== undefined) {
Vue.set(state.statuses[status.id], 'favourited', false)
state.statuses[status.id].favourites_count--
}
},
/**
@ -181,6 +184,7 @@ const mutations = {
boostStatus(state, { status }) {
if (state.statuses[status.id] !== undefined) {
Vue.set(state.statuses[status.id], 'reblogged', true)
state.statuses[status.id].reblogs_count++
}
},
/**
@ -191,6 +195,7 @@ const mutations = {
unboostStatus(state, { status }) {
if (state.statuses[status.id] !== undefined) {
Vue.set(state.statuses[status.id], 'reblogged', false)
state.statuses[status.id].reblogs_count--
}
},
}
@ -210,11 +215,14 @@ const getters = {
.map(statusId => state.statuses[statusId])
.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())
},
getStatus(state) {
return (statusId) => state.statuses[statusId]
},
getSinglePost(state) {
return state.statuses[state.params.singlePost]
},
getPostFromTimeline(state) {
return (/** @type {string} */ statusId) => {
return (statusId) => {
if (state.statuses[statusId] !== undefined) {
return state.statuses[statusId]
} else {
@ -280,11 +288,11 @@ const actions = {
*/
async postDelete(context, status) {
try {
context.commit('removeStatusf', status)
context.commit('removeStatus', status)
const response = await axios.delete(generateUrl(`apps/social/api/v1/post?id=${status.uri}`))
logger.info('Post deleted with token ' + response.data.result.token)
} catch (error) {
context.commit('updateInTimelines', [status])
context.commit('addToStatuses', status)
showError('Failed to delete the status')
logger.error('Failed to delete the status', { error })
}
@ -299,7 +307,7 @@ const actions = {
context.commit('likeStatus', { status })
const response = await axios.post(generateUrl(`apps/social/api/v1/statuses/${status.id}/favourite`))
logger.info('Post liked')
context.commit('updateInTimelines', [response.data])
context.commit('addToStatuses', response.data)
return response
} catch (error) {
context.commit('unlikeStatus', { status })
@ -316,12 +324,12 @@ const actions = {
try {
// Remove status from list if we are in the 'liked' timeline
if (state.type === 'liked') {
context.commit('removeStatusf', status)
context.commit('removeStatus', status)
}
context.commit('unlikeStatus', { status })
const response = await axios.post(generateUrl(`apps/social/api/v1/statuses/${status.id}/unfavourite`))
logger.info('Post unliked')
context.commit('updateInTimelines', [response.data])
context.commit('addToStatuses', response.data)
return response
} catch (error) {
// Readd status from list if we are in the 'liked' timeline
@ -343,7 +351,7 @@ const actions = {
context.commit('boostStatus', { status })
const response = await axios.post(generateUrl(`apps/social/api/v1/statuses/${status.id}/reblog`))
logger.info('Post boosted')
context.commit('updateInTimelines', [response.data])
context.commit('addToStatuses', response.data)
return response
} catch (error) {
context.commit('unboostStatus', { status })
@ -361,7 +369,7 @@ const actions = {
context.commit('unboostStatus', { status })
const response = await axios.post(generateUrl(`apps/social/api/v1/statuses/${status.id}/unreblog`))
logger.info('Boost deleted')
context.commit('updateInTimelines', [response.data])
context.commit('addToStatuses', response.data)
return response
} catch (error) {
context.commit('boostStatus', { status })

Wyświetl plik

@ -24,7 +24,7 @@
<div :class="{'icon-loading': !accountLoaded}" class="social__wrapper">
<ProfileInfo v-if="accountLoaded && accountInfo" :uid="uid" />
<Composer v-if="accountInfo" :initial-mention="accountInfo.acct === currentAccount.acct ? null : accountInfo" default-visibility="direct" />
<Composer v-if="accountInfo && $route.name === 'profile'" :initial-mention="accountInfo.acct === currentAccount.acct ? null : accountInfo" default-visibility="direct" />
<!-- TODO: we have no details, timeline and follower list for non-local accounts for now -->
<router-view v-if="accountLoaded && accountInfo && isLocal" name="details" />