commit: 3e99006e2ab06d2c8ade2eb20e12b1d2fbbcaac2
parent e232ba0ec5542020f83ea685b8fb491b23def627
Author: HJ <30-hj@users.noreply.git.pleroma.social>
Date: Wed, 22 May 2024 12:15:57 +0000
Merge branch 'quotes-count' into 'develop'
Display quotes count on posts and add quotes list page
See merge request pleroma/pleroma-fe!1885
Diffstat:
15 files changed, 85 insertions(+), 11 deletions(-)
diff --git a/changelog.d/quotes-count.add b/changelog.d/quotes-count.add
@@ -0,0 +1 @@
+Display quotes count on posts and add quotes list page
+\ No newline at end of file
diff --git a/src/boot/routes.js b/src/boot/routes.js
@@ -25,6 +25,7 @@ import ListsTimeline from 'components/lists_timeline/lists_timeline.vue'
import ListsEdit from 'components/lists_edit/lists_edit.vue'
import NavPanel from 'src/components/nav_panel/nav_panel.vue'
import AnnouncementsPage from 'components/announcements_page/announcements_page.vue'
+import QuotesTimeline from '../components/quotes_timeline/quotes_timeline.vue'
export default (store) => {
const validateAuthenticatedRoute = (to, from, next) => {
@@ -51,6 +52,7 @@ export default (store) => {
{ name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline },
{ name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline },
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
+ { name: 'quotes', path: '/notice/:id/quotes', component: QuotesTimeline },
{
name: 'remote-user-profile-acct',
path: '/remote-users/:_(@)?:username([^/@]+)@:hostname([^/@]+)',
diff --git a/src/components/quotes_timeline/quotes_timeline.js b/src/components/quotes_timeline/quotes_timeline.js
@@ -0,0 +1,26 @@
+import Timeline from '../timeline/timeline.vue'
+
+const QuotesTimeline = {
+ created () {
+ this.$store.commit('clearTimeline', { timeline: 'quotes' })
+ this.$store.dispatch('startFetchingTimeline', { timeline: 'quotes', statusId: this.statusId })
+ },
+ components: {
+ Timeline
+ },
+ computed: {
+ statusId () { return this.$route.params.id },
+ timeline () { return this.$store.state.statuses.timelines.quotes }
+ },
+ watch: {
+ statusId () {
+ this.$store.commit('clearTimeline', { timeline: 'quotes' })
+ this.$store.dispatch('startFetchingTimeline', { timeline: 'quotes', statusId: this.statusId })
+ }
+ },
+ unmounted () {
+ this.$store.dispatch('stopFetchingTimeline', 'quotes')
+ }
+}
+
+export default QuotesTimeline
diff --git a/src/components/quotes_timeline/quotes_timeline.vue b/src/components/quotes_timeline/quotes_timeline.vue
@@ -0,0 +1,10 @@
+<template>
+ <Timeline
+ :title="$t('nav.quotes')"
+ :timeline="timeline"
+ :timeline-name="'quotes'"
+ :status-id="statusId"
+ />
+</template>
+
+<script src='./quotes_timeline.js'></script>
diff --git a/src/components/status/status.js b/src/components/status/status.js
@@ -373,6 +373,9 @@ const Status = {
hidePostStats () {
return this.mergedConfig.hidePostStats
},
+ shouldDisplayFavsAndRepeats () {
+ return !this.hidePostStats && this.isFocused && (this.combinedFavsAndRepeatsUsers.length > 0 || this.statusFromGlobalRepository.quotes_count)
+ },
muteBotStatuses () {
return this.mergedConfig.muteBotStatuses
},
diff --git a/src/components/status/status.scss b/src/components/status/status.scss
@@ -374,6 +374,7 @@
font-weight: bolder;
font-size: 1.1em;
line-height: 1em;
+ color: var(--text);
}
&:hover .stat-title {
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
@@ -484,7 +484,7 @@
<transition name="fade">
<div
- v-if="!hidePostStats && isFocused && combinedFavsAndRepeatsUsers.length > 0"
+ v-if="shouldDisplayFavsAndRepeats"
class="favs-repeated-users"
>
<div class="stats">
@@ -512,6 +512,19 @@
</div>
</div>
</UserListPopover>
+ <router-link
+ v-if="statusFromGlobalRepository.quotes_count > 0"
+ :to="{ name: 'quotes', params: { id: status.id } }"
+ >
+ <div
+ class="stat-count"
+ >
+ <a class="stat-title">{{ $t('status.quotes') }}</a>
+ <div class="stat-number">
+ {{ statusFromGlobalRepository.quotes_count }}
+ </div>
+ </div>
+ </router-link>
<div class="avatar-row">
<AvatarList :users="combinedFavsAndRepeatsUsers" />
</div>
diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js
@@ -25,6 +25,7 @@ const Timeline = {
'title',
'userId',
'listId',
+ 'statusId',
'tag',
'embedded',
'count',
@@ -121,6 +122,7 @@ const Timeline = {
showImmediately,
userId: this.userId,
listId: this.listId,
+ statusId: this.statusId,
tag: this.tag
})
},
@@ -183,6 +185,7 @@ const Timeline = {
showImmediately: true,
userId: this.userId,
listId: this.listId,
+ statusId: this.statusId,
tag: this.tag
}).then(({ statuses }) => {
if (statuses && statuses.length === 0) {
diff --git a/src/components/timeline_menu/timeline_menu.js b/src/components/timeline_menu/timeline_menu.js
@@ -19,7 +19,8 @@ export const timelineNames = () => {
bookmarks: 'nav.bookmarks',
dms: 'nav.dms',
'public-timeline': 'nav.public_tl',
- 'public-external-timeline': 'nav.twkn'
+ 'public-external-timeline': 'nav.twkn',
+ quotes: 'nav.quotes'
}
}
diff --git a/src/i18n/en.json b/src/i18n/en.json
@@ -189,7 +189,8 @@
"mobile_notifications": "Open notifications (there are unread ones)",
"mobile_notifications_close": "Close notifications",
"mobile_notifications_mark_as_seen": "Mark all as seen",
- "announcements": "Announcements"
+ "announcements": "Announcements",
+ "quotes": "Quotes"
},
"notifications": {
"broken_favorite": "Unknown status, searching for it…",
@@ -1048,6 +1049,7 @@
"status": {
"favorites": "Favorites",
"repeats": "Repeats",
+ "quotes": "Quotes",
"repeat_confirm": "Do you really want to repeat this status?",
"repeat_confirm_title": "Repeat confirmation",
"repeat_confirm_accept_button": "Repeat",
diff --git a/src/modules/api.js b/src/modules/api.js
@@ -202,12 +202,13 @@ const api = {
timeline = 'friends',
tag = false,
userId = false,
- listId = false
+ listId = false,
+ statusId = false
}) {
if (store.state.fetchers[timeline]) return
const fetcher = store.state.backendInteractor.startFetchingTimeline({
- timeline, store, userId, listId, tag
+ timeline, store, userId, listId, statusId, tag
})
store.commit('addFetcher', { fetcherName: timeline, fetcher })
},
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
@@ -108,6 +108,7 @@ const PLEROMA_POST_ANNOUNCEMENT_URL = '/api/v1/pleroma/admin/announcements'
const PLEROMA_EDIT_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements/${id}`
const PLEROMA_DELETE_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements/${id}`
const PLEROMA_SCROBBLES_URL = id => `/api/v1/pleroma/accounts/${id}/scrobbles`
+const PLEROMA_STATUS_QUOTES_URL = id => `/api/v1/pleroma/statuses/${id}/quotes`
const PLEROMA_USER_FAVORITES_TIMELINE_URL = id => `/api/v1/pleroma/accounts/${id}/favourites`
const PLEROMA_ADMIN_CONFIG_URL = '/api/pleroma/admin/config'
@@ -685,6 +686,7 @@ const fetchTimeline = ({
until = false,
userId = false,
listId = false,
+ statusId = false,
tag = false,
withMuted = false,
replyVisibility = 'all',
@@ -702,7 +704,8 @@ const fetchTimeline = ({
favorites: MASTODON_USER_FAVORITES_TIMELINE_URL,
publicFavorites: PLEROMA_USER_FAVORITES_TIMELINE_URL,
tag: MASTODON_TAG_TIMELINE_URL,
- bookmarks: MASTODON_BOOKMARK_TIMELINE_URL
+ bookmarks: MASTODON_BOOKMARK_TIMELINE_URL,
+ quotes: PLEROMA_STATUS_QUOTES_URL
}
const isNotifications = timeline === 'notifications'
const params = []
@@ -721,6 +724,10 @@ const fetchTimeline = ({
url = url(listId)
}
+ if (timeline === 'quotes') {
+ url = url(statusId)
+ }
+
if (minId) {
params.push(['min_id', minId])
}
diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js
@@ -5,8 +5,8 @@ import followRequestFetcher from '../../services/follow_request_fetcher/follow_r
import listsFetcher from '../../services/lists_fetcher/lists_fetcher.service.js'
const backendInteractorService = credentials => ({
- startFetchingTimeline ({ timeline, store, userId = false, listId = false, tag }) {
- return timelineFetcher.startFetching({ timeline, store, credentials, userId, listId, tag })
+ startFetchingTimeline ({ timeline, store, userId = false, listId = false, statusId = false, tag }) {
+ return timelineFetcher.startFetching({ timeline, store, credentials, userId, listId, statusId, tag })
},
fetchTimeline (args) {
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -331,6 +331,7 @@ export const parseStatus = (data) => {
output.quote_id = pleroma.quote_id ? pleroma.quote_id : (output.quote ? output.quote.id : undefined)
output.quote_url = pleroma.quote_url
output.quote_visible = pleroma.quote_visible
+ output.quotes_count = pleroma.quotes_count
} else {
output.text = data.content
output.summary = data.spoiler_text
diff --git a/src/services/timeline_fetcher/timeline_fetcher.service.js b/src/services/timeline_fetcher/timeline_fetcher.service.js
@@ -24,6 +24,7 @@ const fetchAndUpdate = ({
showImmediately = false,
userId = false,
listId = false,
+ statusId = false,
tag = false,
until,
since
@@ -47,6 +48,7 @@ const fetchAndUpdate = ({
args.userId = userId
args.listId = listId
+ args.statusId = statusId
args.tag = tag
args.withMuted = !hideMutedPosts
if (loggedIn && ['friends', 'public', 'publicAndExternal'].includes(timeline)) {
@@ -78,15 +80,15 @@ const fetchAndUpdate = ({
})
}
-const startFetching = ({ timeline = 'friends', credentials, store, userId = false, listId = false, tag = false }) => {
+const startFetching = ({ timeline = 'friends', credentials, store, userId = false, listId = false, statusId = false, tag = false }) => {
const rootState = store.rootState || store.state
const timelineData = rootState.statuses.timelines[camelCase(timeline)]
const showImmediately = timelineData.visibleStatuses.length === 0
timelineData.userId = userId
timelineData.listId = listId
- fetchAndUpdate({ timeline, credentials, store, showImmediately, userId, listId, tag })
+ fetchAndUpdate({ timeline, credentials, store, showImmediately, userId, listId, statusId, tag })
const boundFetchAndUpdate = () =>
- fetchAndUpdate({ timeline, credentials, store, userId, listId, tag })
+ fetchAndUpdate({ timeline, credentials, store, userId, listId, statusId, tag })
return promiseInterval(boundFetchAndUpdate, 10000)
}
const timelineFetcher = {