show number of favs/boosts and favs/boosts page
This commit is contained in:
parent
e7fc226935
commit
de34efc554
19
routes/_api/reblogsAndFavs.js
Normal file
19
routes/_api/reblogsAndFavs.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { get, paramsString } from '../_utils/ajax'
|
||||||
|
|
||||||
|
// TODO: paginate
|
||||||
|
|
||||||
|
export async function getReblogs(instanceName, accessToken, statusId, limit = 80) {
|
||||||
|
let url = `https://${instanceName}/api/v1/statuses/${statusId}/reblogged_by`
|
||||||
|
url += '?' + paramsString({ limit })
|
||||||
|
return get(url, {
|
||||||
|
'Authorization': `Bearer ${accessToken}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getFavorites(instanceName, accessToken, statusId, limit = 80) {
|
||||||
|
let url = `https://${instanceName}/api/v1/statuses/${statusId}/favourited_by`
|
||||||
|
url += '?' + paramsString({ limit })
|
||||||
|
return get(url, {
|
||||||
|
'Authorization': `Bearer ${accessToken}`
|
||||||
|
})
|
||||||
|
}
|
62
routes/_components/AccountsListPage.html
Normal file
62
routes/_components/AccountsListPage.html
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
<div class="accounts-page">
|
||||||
|
{{#if loading}}
|
||||||
|
<LoadingPage />
|
||||||
|
{{elseif accounts && accounts.length}}
|
||||||
|
<ul class="accounts-results">
|
||||||
|
{{#each accounts as account}}
|
||||||
|
<AccountSearchResult :account />
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.accounts-page {
|
||||||
|
min-height: 60vh;
|
||||||
|
padding: 20px 20px;
|
||||||
|
}
|
||||||
|
.accounts-results {
|
||||||
|
list-style: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid var(--main-border);
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.accounts-page {
|
||||||
|
padding: 20px 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
import Layout from '../_components/Layout.html'
|
||||||
|
import { store } from '../_store/store'
|
||||||
|
import LoadingPage from '../_components/LoadingPage.html'
|
||||||
|
import AccountSearchResult from '../_components/search/AccountSearchResult.html'
|
||||||
|
import { toast } from '../_utils/toast'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
async oncreate() {
|
||||||
|
let accountsFetcher = this.get('accountsFetcher')
|
||||||
|
let statusId = this.get('statusId')
|
||||||
|
let instanceName = this.store.get('currentInstance')
|
||||||
|
let accessToken = this.store.get('accessToken')
|
||||||
|
try {
|
||||||
|
let accounts = await accountsFetcher(instanceName, accessToken, statusId)
|
||||||
|
this.set({ accounts: accounts })
|
||||||
|
} catch (e) {
|
||||||
|
toast.say('Error: ' + (e.name || '') + ' ' + (e.message || ''))
|
||||||
|
} finally {
|
||||||
|
this.set({loading: false})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: () => ({
|
||||||
|
loading: true,
|
||||||
|
accounts: []
|
||||||
|
}),
|
||||||
|
store: () => store,
|
||||||
|
components: {
|
||||||
|
Layout,
|
||||||
|
LoadingPage,
|
||||||
|
AccountSearchResult
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -26,7 +26,7 @@
|
||||||
<StatusMediaAttachments status="{{originalStatus}}" :contextualStatusId on:recalculateHeight />
|
<StatusMediaAttachments status="{{originalStatus}}" :contextualStatusId on:recalculateHeight />
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if isStatusInOwnThread}}
|
{{#if isStatusInOwnThread}}
|
||||||
<StatusAbsoluteDate status="{{originalStatus}}" />
|
<StatusDetails status="{{originalStatus}}" />
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<StatusToolbar :status :isStatusInOwnThread />
|
<StatusToolbar :status :isStatusInOwnThread />
|
||||||
</article>
|
</article>
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
"spoiler-btn spoiler-btn"
|
"spoiler-btn spoiler-btn"
|
||||||
"content content"
|
"content content"
|
||||||
"media media"
|
"media media"
|
||||||
"date date"
|
"details details"
|
||||||
"toolbar toolbar";
|
"toolbar toolbar";
|
||||||
grid-template-columns: min-content 1fr;
|
grid-template-columns: min-content 1fr;
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@
|
||||||
import StatusAuthorName from './StatusAuthorName.html'
|
import StatusAuthorName from './StatusAuthorName.html'
|
||||||
import StatusAuthorHandle from './StatusAuthorHandle.html'
|
import StatusAuthorHandle from './StatusAuthorHandle.html'
|
||||||
import StatusRelativeDate from './StatusRelativeDate.html'
|
import StatusRelativeDate from './StatusRelativeDate.html'
|
||||||
import StatusAbsoluteDate from './StatusAbsoluteDate.html'
|
import StatusDetails from './StatusDetails.html'
|
||||||
import StatusToolbar from './StatusToolbar.html'
|
import StatusToolbar from './StatusToolbar.html'
|
||||||
import StatusMediaAttachments from './StatusMediaAttachments.html'
|
import StatusMediaAttachments from './StatusMediaAttachments.html'
|
||||||
import StatusContent from './StatusContent.html'
|
import StatusContent from './StatusContent.html'
|
||||||
|
@ -116,7 +116,7 @@
|
||||||
StatusAuthorName,
|
StatusAuthorName,
|
||||||
StatusAuthorHandle,
|
StatusAuthorHandle,
|
||||||
StatusRelativeDate,
|
StatusRelativeDate,
|
||||||
StatusAbsoluteDate,
|
StatusDetails,
|
||||||
StatusToolbar,
|
StatusToolbar,
|
||||||
StatusMediaAttachments,
|
StatusMediaAttachments,
|
||||||
StatusContent,
|
StatusContent,
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
<ExternalLink class="status-absolute-date" href="{{status.url}}" showIcon="true">
|
|
||||||
<time datetime={{createdAtDate}} title="{{formattedDate}}">{{formattedDate}}</time>
|
|
||||||
</ExternalLink>
|
|
||||||
<style>
|
|
||||||
:global(.status-absolute-date) {
|
|
||||||
grid-area: date;
|
|
||||||
font-size: 1.1em;
|
|
||||||
white-space: nowrap;
|
|
||||||
margin: 0 5px 10px;
|
|
||||||
justify-self: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.status-absolute-date, .status-absolute-date:hover, .status-absolute-date:visited) {
|
|
||||||
color: var(--deemphasized-text-color);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
import ExternalLink from '../ExternalLink.html'
|
|
||||||
|
|
||||||
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
||||||
year: 'numeric',
|
|
||||||
month: 'long',
|
|
||||||
day: 'numeric',
|
|
||||||
hour: '2-digit',
|
|
||||||
minute: '2-digit'
|
|
||||||
})
|
|
||||||
|
|
||||||
export default {
|
|
||||||
computed: {
|
|
||||||
createdAtDate: (status) => status.created_at,
|
|
||||||
formattedDate: (createdAtDate) => formatter.format(new Date(createdAtDate))
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
ExternalLink
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
104
routes/_components/status/StatusDetails.html
Normal file
104
routes/_components/status/StatusDetails.html
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
<div class="status-details">
|
||||||
|
<ExternalLink class="status-absolute-date" href="{{status.url}}" showIcon="true">
|
||||||
|
<time datetime={{createdAtDate}} title="{{formattedDate}}">{{formattedDate}}</time>
|
||||||
|
</ExternalLink>
|
||||||
|
<a class="status-favs-reblogs" href="/statuses/{{statusId}}/reblogs">
|
||||||
|
<svg>
|
||||||
|
<use xlink:href="#fa-retweet"/>
|
||||||
|
</svg>
|
||||||
|
<span>{{numReblogs}}</span>
|
||||||
|
</a>
|
||||||
|
<a class="status-favs-reblogs" href="/statuses/{{statusId}}/favorites">
|
||||||
|
<svg>
|
||||||
|
<use xlink:href="#fa-star" />
|
||||||
|
</svg>
|
||||||
|
<span>{{numFavs}}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.status-details {
|
||||||
|
grid-area: details;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, max-content) min-content min-content;
|
||||||
|
grid-gap: 20px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: left;
|
||||||
|
margin: 0 5px 10px;
|
||||||
|
}
|
||||||
|
:global(.status-absolute-date) {
|
||||||
|
font-size: 1.1em;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.status-absolute-date time) {
|
||||||
|
word-wrap: break-word;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-favs-reblogs {
|
||||||
|
font-size: 1.1em;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-favs-reblogs span {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-favs-reblogs,
|
||||||
|
.status-favs-reblogs:hover,
|
||||||
|
.status-favs-reblogs:visited {
|
||||||
|
color: var(--deemphasized-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-favs-reblogs svg {
|
||||||
|
fill: var(--deemphasized-text-color);
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.status-absolute-date, .status-absolute-date:hover, .status-absolute-date:visited) {
|
||||||
|
color: var(--deemphasized-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 479px) {
|
||||||
|
:global(.status-absolute-date) {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
.status-favs-reblogs {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
.status-details {
|
||||||
|
grid-gap: 5px;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
import ExternalLink from '../ExternalLink.html'
|
||||||
|
|
||||||
|
const formatter = new Intl.DateTimeFormat('en-US', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'long',
|
||||||
|
day: 'numeric',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit'
|
||||||
|
})
|
||||||
|
|
||||||
|
export default {
|
||||||
|
computed: {
|
||||||
|
statusId: (status) => status.id,
|
||||||
|
createdAtDate: (status) => status.created_at,
|
||||||
|
numReblogs: (status) => status.reblogs_count || 0,
|
||||||
|
numFavs: (status) => status.favourites_count || 0,
|
||||||
|
formattedDate: (createdAtDate) => formatter.format(new Date(createdAtDate))
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
ExternalLink
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
25
routes/statuses/[statusId]/favorites.html
Normal file
25
routes/statuses/[statusId]/favorites.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<:Head>
|
||||||
|
<title>Pinafore – Favorites</title>
|
||||||
|
</:Head>
|
||||||
|
|
||||||
|
<Layout page='favorites'>
|
||||||
|
<AccountsListPage :accountsFetcher :statusId />
|
||||||
|
</Layout>
|
||||||
|
<script>
|
||||||
|
import Layout from '../../_components/Layout.html'
|
||||||
|
import { getFavorites } from '../../_api/reblogsAndFavs'
|
||||||
|
import AccountsListPage from '../../_components/AccountsListPage.html'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data: () => ({
|
||||||
|
accountsFetcher: getFavorites
|
||||||
|
}),
|
||||||
|
computed: {
|
||||||
|
statusId: params => params.statusId
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Layout,
|
||||||
|
AccountsListPage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -17,12 +17,12 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</Layout>
|
</Layout>
|
||||||
<script>
|
<script>
|
||||||
import Layout from '../_components/Layout.html'
|
import Layout from '../../_components/Layout.html'
|
||||||
import LazyTimeline from '../_components/timeline/LazyTimeline.html'
|
import LazyTimeline from '../../_components/timeline/LazyTimeline.html'
|
||||||
import FreeTextLayout from '../_components/FreeTextLayout.html'
|
import FreeTextLayout from '../../_components/FreeTextLayout.html'
|
||||||
import { store } from '../_store/store.js'
|
import { store } from '../../_store/store.js'
|
||||||
import HiddenFromSSR from '../_components/HiddenFromSSR'
|
import HiddenFromSSR from '../../_components/HiddenFromSSR'
|
||||||
import DynamicPageBanner from '../_components/DynamicPageBanner.html'
|
import DynamicPageBanner from '../../_components/DynamicPageBanner.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
store: () => store,
|
store: () => store,
|
25
routes/statuses/[statusId]/reblogs.html
Normal file
25
routes/statuses/[statusId]/reblogs.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<:Head>
|
||||||
|
<title>Pinafore – Reblogs</title>
|
||||||
|
</:Head>
|
||||||
|
|
||||||
|
<Layout page='reblogs'>
|
||||||
|
<AccountsListPage :accountsFetcher :statusId />
|
||||||
|
</Layout>
|
||||||
|
<script>
|
||||||
|
import Layout from '../../_components/Layout.html'
|
||||||
|
import { getReblogs } from '../../_api/reblogsAndFavs'
|
||||||
|
import AccountsListPage from '../../_components/AccountsListPage.html'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data: () => ({
|
||||||
|
accountsFetcher: getReblogs
|
||||||
|
}),
|
||||||
|
computed: {
|
||||||
|
statusId: params => params.statusId
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Layout,
|
||||||
|
AccountsListPage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
Loading…
Reference in a new issue