summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLouis <6653109+artonge@users.noreply.github.com>2023-04-20 20:03:40 +0200
committerGitHub <noreply@github.com>2023-04-20 20:03:40 +0200
commit281373117b2b2758863a2e3657316e3f9bbca93d (patch)
treeefa1cf251996a920a4ca6f524623bd09dee609ba
parent7c80556ae4257ccc196428b7ef6d6abf170a4288 (diff)
parent8418364b9fa76e1ddc5ca611c80ca11c4df0aade (diff)
Merge pull request #1744 from nextcloud/artonge/fix/fixes
Front-end fixes
-rw-r--r--src/components/Composer/Composer.vue20
-rw-r--r--src/components/Composer/SubmitStatusButton.vue2
-rw-r--r--src/components/FollowButton.vue4
-rw-r--r--src/components/ProfileInfo.vue2
-rw-r--r--src/components/TimelineAvatar.vue4
-rw-r--r--src/components/TimelineEntry.vue101
-rw-r--r--src/components/TimelinePost.vue48
-rw-r--r--src/components/UserEntry.vue7
-rw-r--r--src/components/Visibility/VisibilitiesInfos.js2
-rw-r--r--src/store/account.js4
-rw-r--r--src/store/timeline.js56
-rw-r--r--src/views/Profile.vue2
12 files changed, 126 insertions, 126 deletions
diff --git a/src/components/Composer/Composer.vue b/src/components/Composer/Composer.vue
index e0a77ecc..d3c73e7e 100644
--- a/src/components/Composer/Composer.vue
+++ b/src/components/Composer/Composer.vue
@@ -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);
diff --git a/src/components/Composer/SubmitStatusButton.vue b/src/components/Composer/SubmitStatusButton.vue
index f426efd3..caf09655 100644
--- a/src/components/Composer/SubmitStatusButton.vue
+++ b/src/components/Composer/SubmitStatusButton.vue
@@ -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 ''
},
diff --git a/src/components/FollowButton.vue b/src/components/FollowButton.vue
index 3390c1fc..01b17c0e 100644
--- a/src/components/FollowButton.vue
+++ b/src/components/FollowButton.vue
@@ -72,10 +72,6 @@ export default {
currentUser,
],
props: {
- account: {
- type: String,
- default: '',
- },
uid: {
type: String,
default: '',
diff --git a/src/components/ProfileInfo.vue b/src/components/ProfileInfo.vue
index ed2e384b..c40d1452 100644
--- a/src/components/ProfileInfo.vue
+++ b/src/components/ProfileInfo.vue
@@ -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">
diff --git a/src/components/TimelineAvatar.vue b/src/components/TimelineAvatar.vue
index 11aeb658..17e6bcc0 100644
--- a/src/components/TimelineAvatar.vue
+++ b/src/components/TimelineAvatar.vue
@@ -48,9 +48,5 @@ export default {
padding: 5px 10px 10px 5px;
height: 52px;
width: 52px;
-
- .avatardiv {
- position: static;
- }
}
</style>
diff --git a/src/components/TimelineEntry.vue b/src/components/TimelineEntry.vue
index 80812f1a..6e4fd50b 100644
--- a/src/components/TimelineEntry.vue
+++ b/src/components/TimelineEntry.vue
@@ -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>
diff --git a/src/components/TimelinePost.vue b/src/components/TimelinePost.vue
index 1b23b79b..6cd0c10b 100644
--- a/src/components/TimelinePost.vue
+++ b/src/components/TimelinePost.vue
@@ -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>
diff --git a/src/components/UserEntry.vue b/src/components/UserEntry.vue
index 370753ca..ca52c85e 100644
--- a/src/components/UserEntry.vue
+++ b/src/components/UserEntry.vue
@@ -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">
diff --git a/src/components/Visibility/VisibilitiesInfos.js b/src/components/Visibility/VisibilitiesInfos.js
index af2c64c0..e7955d30 100644
--- a/src/components/Visibility/VisibilitiesInfos.js
+++ b/src/components/Visibility/VisibilitiesInfos.js
@@ -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'),
},
]
diff --git a/src/store/account.js b/src/store/account.js
index 01f59336..43ea3b26 100644
--- a/src/store/account.js
+++ b/src/store/account.js
@@ -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) {
diff --git a/src/store/timeline.js b/src/store/timeline.js
index e972c0a1..44f138c8 100644
--- a/src/store/timeline.js
+++ b/src/store/timeline.js
@@ -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)
@@ -102,20 +114,9 @@ const mutations = {
},
/**
* @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 })
diff --git a/src/views/Profile.vue b/src/views/Profile.vue
index f0fae400..fbb29955 100644
--- a/src/views/Profile.vue
+++ b/src/views/Profile.vue
@@ -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" />