diff --git a/src/components/avatar_list/avatar_list.js b/src/components/avatar_list/avatar_list.js
new file mode 100644
index 00000000..d65125c2
--- /dev/null
+++ b/src/components/avatar_list/avatar_list.js
@@ -0,0 +1,15 @@
+import UserAvatar from '../user_avatar/user_avatar.vue'
+
+const AvatarList = {
+ props: ['avatars'],
+ computed: {
+ slicedAvatars () {
+ return this.avatars ? this.avatars.slice(0, 15) : []
+ }
+ },
+ components: {
+ UserAvatar
+ }
+}
+
+export default AvatarList
diff --git a/src/components/avatar_list/avatar_list.vue b/src/components/avatar_list/avatar_list.vue
new file mode 100644
index 00000000..b14474ba
--- /dev/null
+++ b/src/components/avatar_list/avatar_list.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js
index 30600f73..ffeb7244 100644
--- a/src/components/conversation/conversation.js
+++ b/src/components/conversation/conversation.js
@@ -139,6 +139,7 @@ const conversation = {
},
setHighlight (id) {
this.highlight = id
+ this.$store.dispatch('fetchFavsAndRepeats', id)
},
getHighlight () {
return this.isExpanded ? this.highlight : null
diff --git a/src/components/status/status.js b/src/components/status/status.js
index 0295cd04..f10eb2e4 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -7,11 +7,12 @@ import UserCard from '../user_card/user_card.vue'
import UserAvatar from '../user_avatar/user_avatar.vue'
import Gallery from '../gallery/gallery.vue'
import LinkPreview from '../link-preview/link-preview.vue'
+import AvatarList from '../avatar_list/avatar_list.vue'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import fileType from 'src/services/file_type/file_type.service'
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
import { mentionMatchesUrl, extractTagFromUrl } from 'src/services/matcher/matcher.service.js'
-import { filter, find, unescape } from 'lodash'
+import { filter, find, unescape, uniqBy } from 'lodash'
const Status = {
name: 'Status',
@@ -97,6 +98,10 @@ const Status = {
return this.statusoid
}
},
+ statusFromGlobalRepository () {
+ // NOTE: Consider to replace status with statusFromGlobalRepository
+ return this.$store.state.statuses.allStatusesObject[this.status.id]
+ },
loggedIn () {
return !!this.$store.state.users.currentUser
},
@@ -257,6 +262,14 @@ const Status = {
return this.status.statusnet_html
}
return this.status.summary_html + '
' + this.status.statusnet_html
+ },
+ combinedFavsAndRepeatsAvatars () {
+ // Use the status from the global status repository since favs and repeats are saved in it
+ const combinedAvatars = [].concat(
+ this.statusFromGlobalRepository.favoritedBy,
+ this.statusFromGlobalRepository.rebloggedBy
+ )
+ return uniqBy(combinedAvatars, 'id')
}
},
components: {
@@ -268,7 +281,8 @@ const Status = {
UserCard,
UserAvatar,
Gallery,
- LinkPreview
+ LinkPreview,
+ AvatarList
},
methods: {
visibilityIcon (visibility) {
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 690e8318..a5f7429c 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -133,6 +133,24 @@
+
+
+
+
@@ -612,6 +630,50 @@ a.unmute {
}
}
+.favs-repeated-users {
+ margin-top: $status-margin;
+
+ .stats {
+ width: 100%;
+ display: flex;
+ line-height: 1em;
+
+ .stat-count {
+ margin-right: $status-margin;
+
+ .stat-title {
+ color: var(--faint, $fallback--faint);
+ font-size: 12px;
+ text-transform: uppercase;
+ position: relative;
+ }
+
+ .stat-number {
+ font-weight: bolder;
+ font-size: 16px;
+ line-height: 1em;
+ }
+ }
+
+ .avatar-row {
+ flex: 1;
+ overflow: hidden;
+ position: relative;
+ display: flex;
+ align-items: center;
+
+ &::before {
+ content: '';
+ position: absolute;
+ height: 100%;
+ width: 1px;
+ left: 0;
+ background-color: var(--faint, $fallback--faint);
+ }
+ }
+ }
+}
+
@media all and (max-width: 800px) {
.status-el {
.retweet-info {
diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue
index e0a34bd1..e6a8d458 100644
--- a/src/components/timeline/timeline.vue
+++ b/src/components/timeline/timeline.vue
@@ -16,7 +16,7 @@
-
+ commit(
+ 'addFavsAndRepeats',
+ {
+ id,
+ favoritedByUsers: favoritedByUsers.filter(_ => _),
+ rebloggedByUsers: rebloggedByUsers.filter(_ => _)
+ }
+ )
+ )
}
},
mutations
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index 6d789f47..c5e2280d 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -47,6 +47,8 @@ const MASTODON_MUTE_USER_URL = id => `/api/v1/accounts/${id}/mute`
const MASTODON_UNMUTE_USER_URL = id => `/api/v1/accounts/${id}/unmute`
const MASTODON_POST_STATUS_URL = '/api/v1/statuses'
const MASTODON_MEDIA_UPLOAD_URL = '/api/v1/media'
+const MASTODON_STATUS_FAVORITEDBY_URL = id => `/api/v1/statuses/${id}/favourited_by`
+const MASTODON_STATUS_REBLOGGEDBY_URL = id => `/api/v1/statuses/${id}/reblogged_by`
const MASTODON_PROFILE_UPDATE_URL = '/api/v1/accounts/update_credentials'
import { each, map, concat, last } from 'lodash'
@@ -712,6 +714,14 @@ const markNotificationsAsSeen = ({id, credentials}) => {
}).then((data) => data.json())
}
+const fetchFavoritedByUsers = ({id}) => {
+ return promisedRequest(MASTODON_STATUS_FAVORITEDBY_URL(id)).then((users) => users.map(parseUser))
+}
+
+const fetchRebloggedByUsers = ({id}) => {
+ return promisedRequest(MASTODON_STATUS_REBLOGGEDBY_URL(id)).then((users) => users.map(parseUser))
+}
+
const apiService = {
verifyCredentials,
fetchTimeline,
@@ -761,7 +771,9 @@ const apiService = {
approveUser,
denyUser,
suggestions,
- markNotificationsAsSeen
+ markNotificationsAsSeen,
+ fetchFavoritedByUsers,
+ fetchRebloggedByUsers
}
export default apiService
diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js
index b6f070fe..d2b581ca 100644
--- a/src/services/backend_interactor_service/backend_interactor_service.js
+++ b/src/services/backend_interactor_service/backend_interactor_service.js
@@ -113,6 +113,9 @@ const backendInteractorService = (credentials) => {
const deleteAccount = ({password}) => apiService.deleteAccount({credentials, password})
const changePassword = ({password, newPassword, newPasswordConfirmation}) => apiService.changePassword({credentials, password, newPassword, newPasswordConfirmation})
+ const fetchFavoritedByUsers = (id) => apiService.fetchFavoritedByUsers({id})
+ const fetchRebloggedByUsers = (id) => apiService.fetchRebloggedByUsers({id})
+
const backendInteractorServiceInstance = {
fetchStatus,
fetchConversation,
@@ -154,7 +157,9 @@ const backendInteractorService = (credentials) => {
changePassword,
fetchFollowRequests,
approveUser,
- denyUser
+ denyUser,
+ fetchFavoritedByUsers,
+ fetchRebloggedByUsers
}
return backendInteractorServiceInstance