add blocked accounts, muted accounts, pinned toots

This commit is contained in:
Nolan Lawson 2018-02-10 16:03:28 -08:00
parent de34efc554
commit 02afea70ed
13 changed files with 242 additions and 35 deletions

View File

@ -21,6 +21,8 @@ module.exports = [
{id: 'fa-search', src: 'node_modules/font-awesome-svg-png/white/svg/search.svg', title: 'Search'}, {id: 'fa-search', src: 'node_modules/font-awesome-svg-png/white/svg/search.svg', title: 'Search'},
{id: 'fa-comments', src: 'node_modules/font-awesome-svg-png/white/svg/comments.svg', title: 'Conversations'}, {id: 'fa-comments', src: 'node_modules/font-awesome-svg-png/white/svg/comments.svg', title: 'Conversations'},
{id: 'fa-paperclip', src: 'node_modules/font-awesome-svg-png/white/svg/paperclip.svg', title: 'Paperclip'}, {id: 'fa-paperclip', src: 'node_modules/font-awesome-svg-png/white/svg/paperclip.svg', title: 'Paperclip'},
{id: 'fa-thumbtack', src: 'node_modules/font-awesome-svg-png/white/svg/thumb-tack.svg', title: 'Thumbtack'}, {id: 'fa-thumb-tack', src: 'node_modules/font-awesome-svg-png/white/svg/thumb-tack.svg', title: 'Thumbtack'},
{id: 'fa-bars', src: 'node_modules/font-awesome-svg-png/white/svg/bars.svg', title: 'List'} {id: 'fa-bars', src: 'node_modules/font-awesome-svg-png/white/svg/bars.svg', title: 'List'},
{id: 'fa-volume-off', src: 'node_modules/font-awesome-svg-png/white/svg/volume-off.svg', title: 'Volume off'},
{id: 'fa-ban', src: 'node_modules/font-awesome-svg-png/white/svg/ban.svg', title: 'Ban'},
] ]

View File

@ -0,0 +1,17 @@
import { get, paramsString } from '../_utils/ajax'
export async function getBlockedAccounts(instanceName, accessToken, limit = 80) {
let url = `https://${instanceName}/api/v1/blocks`
url += '?' + paramsString({ limit })
return get(url, {
'Authorization': `Bearer ${accessToken}`
})
}
export async function getMutedAccounts(instanceName, accessToken, limit = 80) {
let url = `https://${instanceName}/api/v1/mutes`
url += '?' + paramsString({ limit })
return get(url, {
'Authorization': `Bearer ${accessToken}`
})
}

View File

@ -0,0 +1,12 @@
import { get, paramsString } from '../_utils/ajax'
export async function getPinnedStatuses(instanceName, accessToken, accountId) {
let url = `https://${instanceName}/api/v1/accounts/${accountId}/statuses`
url += '?' + paramsString({
limit: 40,
pinned: true
})
return get(url, {
'Authorization': `Bearer ${accessToken}`
})
}

View File

@ -1,7 +1,5 @@
import { get, paramsString } from '../_utils/ajax' import { get, paramsString } from '../_utils/ajax'
// TODO: paginate
export async function getReblogs(instanceName, accessToken, statusId, limit = 80) { export async function getReblogs(instanceName, accessToken, statusId, limit = 80) {
let url = `https://${instanceName}/api/v1/statuses/${statusId}/reblogged_by` let url = `https://${instanceName}/api/v1/statuses/${statusId}/reblogged_by`
url += '?' + paramsString({ limit }) url += '?' + paramsString({ limit })

View File

@ -13,6 +13,7 @@
.accounts-page { .accounts-page {
min-height: 60vh; min-height: 60vh;
padding: 20px 20px; padding: 20px 20px;
position: relative;
} }
.accounts-results { .accounts-results {
list-style: none; list-style: none;
@ -36,11 +37,9 @@
export default { export default {
async oncreate() { async oncreate() {
let accountsFetcher = this.get('accountsFetcher') let accountsFetcher = this.get('accountsFetcher')
let statusId = this.get('statusId')
let instanceName = this.store.get('currentInstance')
let accessToken = this.store.get('accessToken')
try { try {
let accounts = await accountsFetcher(instanceName, accessToken, statusId) // TODO: paginate
let accounts = await accountsFetcher()
this.set({ accounts: accounts }) this.set({ accounts: accounts })
} catch (e) { } catch (e) {
toast.say('Error: ' + (e.name || '') + ' ' + (e.message || '')) toast.say('Error: ' + (e.name || '') + ' ' + (e.message || ''))

28
routes/blocked.html Normal file
View File

@ -0,0 +1,28 @@
<:Head>
<title>Pinafore Blocked users</title>
</:Head>
<Layout page='blocked'>
<DynamicPageBanner title="Blocked users" icon="#fa-ban" />
<AccountsListPage :accountsFetcher />
</Layout>
<script>
import Layout from './_components/Layout.html'
import AccountsListPage from './_components/AccountsListPage.html'
import { store } from './_store/store'
import { getBlockedAccounts } from './_api/blockedAndMuted'
import DynamicPageBanner from './_components/DynamicPageBanner.html'
export default {
computed: {
statusId: params => params.statusId,
accountsFetcher: ($currentInstance, $accessToken, statusId) => () => getBlockedAccounts($currentInstance, $accessToken, statusId)
},
store: () => store,
components: {
Layout,
AccountsListPage,
DynamicPageBanner
}
}
</script>

View File

@ -6,12 +6,13 @@
<span aria-label="{{label}} {{$pinnedPage === href ? 'Pinned page' : 'Unpinned page'}}"> <span aria-label="{{label}} {{$pinnedPage === href ? 'Pinned page' : 'Unpinned page'}}">
{{label}} {{label}}
</span> </span>
{{#if pinnable}}
<IconButton pressable="true" <IconButton pressable="true"
pressed="{{$pinnedPage === href}}" pressed="{{$pinnedPage === href}}"
label="Pin page" label="Pin page"
href="#fa-thumbtack" href="#fa-thumb-tack"
on:click="onPinClick(event)" on:click="onPinClick(event)" />
/> {{/if}}
</a> </a>
</li> </li>
<style> <style>

View File

@ -5,27 +5,66 @@
<Layout page='community'> <Layout page='community'>
{{#if $isUserLoggedIn}} {{#if $isUserLoggedIn}}
<div class="community-page"> <div class="community-page">
<PageList label="Community list">
<h2 class="community-header">
Timelines
</h2>
<PageList label="Timelines">
<PageListItem href="/local" <PageListItem href="/local"
label="Local Timeline" label="Local Timeline"
icon="#fa-users" icon="#fa-users"
pinnable="true"
/> />
<PageListItem href="/federated" <PageListItem href="/federated"
label="Federated Timeline" label="Federated Timeline"
icon="#fa-globe" icon="#fa-globe"
pinnable="true"
/> />
<PageListItem href="/favorites" <PageListItem href="/favorites"
label="Favorites" label="Favorites"
icon="#fa-star" icon="#fa-star"
pinnable="true"
/> />
</PageList>
{{#if $lists.length}}
<h2 class="community-header">
Lists
</h2>
<PageList label="Lists">
{{#each $lists as list}} {{#each $lists as list}}
<PageListItem href="/lists/{{list.id}}" <PageListItem href="/lists/{{list.id}}"
label="{{list.title}}" label="{{list.title}}"
icon="#fa-bars" icon="#fa-bars"
pinnable="true"
/> />
{{/each}} {{/each}}
</PageList> </PageList>
{{/if}}
<h2 class="community-header">
Instance settings
</h2>
<PageList label="Instance settings">
<PageListItem href="/muted"
label="Muted users"
icon="#fa-volume-off"
/>
<PageListItem href="/blocked"
label="Blocked users"
icon="#fa-ban"
/>
<PageListItem href="/pinned"
label="Pinned toots"
icon="#fa-thumb-tack"
/>
</PageList>
</div> </div>
{{else}} {{else}}
<HiddenFromSSR> <HiddenFromSSR>

28
routes/muted.html Normal file
View File

@ -0,0 +1,28 @@
<:Head>
<title>Pinafore Muted users</title>
</:Head>
<Layout page='muted'>
<DynamicPageBanner title="Muted users" icon="#fa-volume-off" />
<AccountsListPage :accountsFetcher />
</Layout>
<script>
import Layout from './_components/Layout.html'
import AccountsListPage from './_components/AccountsListPage.html'
import { store } from './_store/store'
import { getMutedAccounts } from './_api/blockedAndMuted'
import DynamicPageBanner from './_components/DynamicPageBanner.html'
export default {
computed: {
statusId: params => params.statusId,
accountsFetcher: ($currentInstance, $accessToken, statusId) => () => getMutedAccounts($currentInstance, $accessToken, statusId)
},
store: () => store,
components: {
Layout,
AccountsListPage,
DynamicPageBanner
}
}
</script>

75
routes/pinned.html Normal file
View File

@ -0,0 +1,75 @@
<:Head>
<title>Pinafore Pinned toots</title>
</:Head>
<Layout page='pinned'>
<DynamicPageBanner title="Pinned toots" icon="#fa-thumb-tack" />
<div class="pinned-toots-page">
{{#if loading}}
<LoadingPage />
{{elseif statuses && statuses.length}}
<ul class="pinned-toots-results">
{{#each statuses as status}}
<StatusSearchResult :status />
{{/each}}
</ul>
{{/if}}
</div>
</Layout>
<style>
.pinned-toots-page {
min-height: 60vh;
padding: 20px 20px;
position: relative;
}
.pinned-toots-results {
list-style: none;
box-sizing: border-box;
border: 1px solid var(--main-border);
border-radius: 2px;
}
@media (max-width: 767px) {
.pinned-toots-page {
padding: 20px 10px;
}
}
</style>
<script>
import Layout from './_components/Layout.html'
import { store } from './_store/store'
import LoadingPage from './_components/LoadingPage.html'
import StatusSearchResult from './_components/search/StatusSearchResult.html'
import { toast } from './_utils/toast'
import DynamicPageBanner from './_components/DynamicPageBanner.html'
import { getPinnedStatuses } from './_api/pinnedStatuses'
import { updateVerifyCredentialsForInstance } from './_actions/instances'
export default {
async oncreate() {
let accountsFetcher = this.get('accountsFetcher')
try {
let currentInstance = this.store.get('currentInstance')
await updateVerifyCredentialsForInstance(currentInstance)
let accessToken = this.store.get('accessToken')
let verifyCredentials = this.store.get('currentVerifyCredentials')
let statuses = await getPinnedStatuses(currentInstance, accessToken, verifyCredentials.id)
this.set({ statuses: statuses })
} catch (e) {
toast.say('Error: ' + (e.name || '') + ' ' + (e.message || ''))
} finally {
this.set({loading: false})
}
},
data: () => ({
loading: true,
accounts: []
}),
store: () => store,
components: {
Layout,
LoadingPage,
StatusSearchResult,
DynamicPageBanner
}
}
</script>

View File

@ -3,23 +3,26 @@
</:Head> </:Head>
<Layout page='favorites'> <Layout page='favorites'>
<AccountsListPage :accountsFetcher :statusId /> <DynamicPageBanner title="Favorites" icon="#fa-star" />
<AccountsListPage :accountsFetcher />
</Layout> </Layout>
<script> <script>
import Layout from '../../_components/Layout.html' import Layout from '../../_components/Layout.html'
import { getFavorites } from '../../_api/reblogsAndFavs' import { getFavorites } from '../../_api/reblogsAndFavs'
import AccountsListPage from '../../_components/AccountsListPage.html' import AccountsListPage from '../../_components/AccountsListPage.html'
import { store } from '../../_store/store'
import DynamicPageBanner from '../../_components/DynamicPageBanner.html'
export default { export default {
data: () => ({
accountsFetcher: getFavorites
}),
computed: { computed: {
statusId: params => params.statusId statusId: params => params.statusId,
accountsFetcher: ($currentInstance, $accessToken, statusId) => () => getFavorites($currentInstance, $accessToken, statusId)
}, },
store: () => store,
components: { components: {
Layout, Layout,
AccountsListPage AccountsListPage,
DynamicPageBanner
} }
} }
</script> </script>

View File

@ -3,23 +3,26 @@
</:Head> </:Head>
<Layout page='reblogs'> <Layout page='reblogs'>
<AccountsListPage :accountsFetcher :statusId /> <DynamicPageBanner title="Boosts" icon="#fa-retweet" />
<AccountsListPage :accountsFetcher />
</Layout> </Layout>
<script> <script>
import Layout from '../../_components/Layout.html' import Layout from '../../_components/Layout.html'
import { getReblogs } from '../../_api/reblogsAndFavs' import { getReblogs } from '../../_api/reblogsAndFavs'
import AccountsListPage from '../../_components/AccountsListPage.html' import AccountsListPage from '../../_components/AccountsListPage.html'
import { store } from '../../_store/store'
import DynamicPageBanner from '../../_components/DynamicPageBanner.html'
export default { export default {
data: () => ({
accountsFetcher: getReblogs
}),
computed: { computed: {
statusId: params => params.statusId statusId: params => params.statusId,
accountsFetcher: ($currentInstance, $accessToken, statusId) => () => getReblogs($currentInstance, $accessToken, statusId)
}, },
store: () => store,
components: { components: {
Layout, Layout,
AccountsListPage AccountsListPage,
DynamicPageBanner
} }
} }
</script> </script>

View File

@ -86,8 +86,10 @@ body.offline,body.theme-hotpants.offline,body.theme-majesty.offline,body.theme-o
<symbol id="fa-search" viewBox="0 0 1792 1792"><title>Search</title><path d="M1216 832q0-185-131.5-316.5T768 384 451.5 515.5 320 832t131.5 316.5T768 1280t316.5-131.5T1216 832zm512 832q0 52-38 90t-90 38q-54 0-90-38l-343-342q-179 124-399 124-143 0-273.5-55.5t-225-150-150-225T64 832t55.5-273.5 150-225 225-150T768 128t273.5 55.5 225 150 150 225T1472 832q0 220-124 399l343 343q37 37 37 90z"></path></symbol> <symbol id="fa-search" viewBox="0 0 1792 1792"><title>Search</title><path d="M1216 832q0-185-131.5-316.5T768 384 451.5 515.5 320 832t131.5 316.5T768 1280t316.5-131.5T1216 832zm512 832q0 52-38 90t-90 38q-54 0-90-38l-343-342q-179 124-399 124-143 0-273.5-55.5t-225-150-150-225T64 832t55.5-273.5 150-225 225-150T768 128t273.5 55.5 225 150 150 225T1472 832q0 220-124 399l343 343q37 37 37 90z"></path></symbol>
<symbol id="fa-comments" viewBox="0 0 1792 1792"><title>Conversations</title><path d="M1408 768q0 139-94 257t-256.5 186.5T704 1280q-86 0-176-16-124 88-278 128-36 9-86 16h-3q-11 0-20.5-8t-11.5-21q-1-3-1-6.5t.5-6.5 2-6l2.5-5 3.5-5.5 4-5 4.5-5 4-4.5q5-6 23-25t26-29.5 22.5-29 25-38.5 20.5-44q-124-72-195-177T0 768q0-139 94-257t256.5-186.5T704 256t353.5 68.5T1314 511t94 257zm384 256q0 120-71 224.5T1526 1425q10 24 20.5 44t25 38.5 22.5 29 26 29.5 23 25q1 1 4 4.5t4.5 5 4 5 3.5 5.5l2.5 5 2 6 .5 6.5-1 6.5q-3 14-13 22t-22 7q-50-7-86-16-154-40-278-128-90 16-176 16-271 0-472-132 58 4 88 4 161 0 309-45t264-129q125-92 192-212t67-254q0-77-23-152 129 71 204 178t75 230z"></path></symbol> <symbol id="fa-comments" viewBox="0 0 1792 1792"><title>Conversations</title><path d="M1408 768q0 139-94 257t-256.5 186.5T704 1280q-86 0-176-16-124 88-278 128-36 9-86 16h-3q-11 0-20.5-8t-11.5-21q-1-3-1-6.5t.5-6.5 2-6l2.5-5 3.5-5.5 4-5 4.5-5 4-4.5q5-6 23-25t26-29.5 22.5-29 25-38.5 20.5-44q-124-72-195-177T0 768q0-139 94-257t256.5-186.5T704 256t353.5 68.5T1314 511t94 257zm384 256q0 120-71 224.5T1526 1425q10 24 20.5 44t25 38.5 22.5 29 26 29.5 23 25q1 1 4 4.5t4.5 5 4 5 3.5 5.5l2.5 5 2 6 .5 6.5-1 6.5q-3 14-13 22t-22 7q-50-7-86-16-154-40-278-128-90 16-176 16-271 0-472-132 58 4 88 4 161 0 309-45t264-129q125-92 192-212t67-254q0-77-23-152 129 71 204 178t75 230z"></path></symbol>
<symbol id="fa-paperclip" viewBox="0 0 1792 1792"><title>Paperclip</title><path d="M1596 1385q0 117-79 196t-196 79q-135 0-235-100L309 784Q196 669 196 513q0-159 110-270t269-111q158 0 273 113l605 606q10 10 10 22 0 16-30.5 46.5T1386 950q-13 0-23-10L757 333q-79-77-181-77-106 0-179 75t-73 181q0 105 76 181l776 777q63 63 145 63 64 0 106-42t42-106q0-82-63-145L825 659q-26-24-60-24-29 0-48 19t-19 48q0 32 25 59l410 410q10 10 10 22 0 16-31 47t-47 31q-12 0-22-10L633 851q-63-61-63-149 0-82 57-139t139-57q88 0 149 63l581 581q100 98 100 235z"></path></symbol> <symbol id="fa-paperclip" viewBox="0 0 1792 1792"><title>Paperclip</title><path d="M1596 1385q0 117-79 196t-196 79q-135 0-235-100L309 784Q196 669 196 513q0-159 110-270t269-111q158 0 273 113l605 606q10 10 10 22 0 16-30.5 46.5T1386 950q-13 0-23-10L757 333q-79-77-181-77-106 0-179 75t-73 181q0 105 76 181l776 777q63 63 145 63 64 0 106-42t42-106q0-82-63-145L825 659q-26-24-60-24-29 0-48 19t-19 48q0 32 25 59l410 410q10 10 10 22 0 16-31 47t-47 31q-12 0-22-10L633 851q-63-61-63-149 0-82 57-139t139-57q88 0 149 63l581 581q100 98 100 235z"></path></symbol>
<symbol id="fa-thumbtack" viewBox="0 0 1792 1792"><title>Thumbtack</title><path d="M800 864V416q0-14-9-23t-23-9-23 9-9 23v448q0 14 9 23t23 9 23-9 9-23zm672 352q0 26-19 45t-45 19H979l-51 483q-2 12-10.5 20.5T897 1792h-1q-27 0-32-27l-76-485H384q-26 0-45-19t-19-45q0-123 78.5-221.5T576 896V384q-52 0-90-38t-38-90 38-90 90-38h640q52 0 90 38t38 90-38 90-90 38v512q99 0 177.5 98.5T1472 1216z"></path></symbol> <symbol id="fa-thumb-tack" viewBox="0 0 1792 1792"><title>Thumbtack</title><path d="M800 864V416q0-14-9-23t-23-9-23 9-9 23v448q0 14 9 23t23 9 23-9 9-23zm672 352q0 26-19 45t-45 19H979l-51 483q-2 12-10.5 20.5T897 1792h-1q-27 0-32-27l-76-485H384q-26 0-45-19t-19-45q0-123 78.5-221.5T576 896V384q-52 0-90-38t-38-90 38-90 90-38h640q52 0 90 38t38 90-38 90-90 38v512q99 0 177.5 98.5T1472 1216z"></path></symbol>
<symbol id="fa-bars" viewBox="0 0 1792 1792"><title>List</title><path d="M1664 1344v128q0 26-19 45t-45 19H192q-26 0-45-19t-19-45v-128q0-26 19-45t45-19h1408q26 0 45 19t19 45zm0-512v128q0 26-19 45t-45 19H192q-26 0-45-19t-19-45V832q0-26 19-45t45-19h1408q26 0 45 19t19 45zm0-512v128q0 26-19 45t-45 19H192q-26 0-45-19t-19-45V320q0-26 19-45t45-19h1408q26 0 45 19t19 45z"></path></symbol> <symbol id="fa-bars" viewBox="0 0 1792 1792"><title>List</title><path d="M1664 1344v128q0 26-19 45t-45 19H192q-26 0-45-19t-19-45v-128q0-26 19-45t45-19h1408q26 0 45 19t19 45zm0-512v128q0 26-19 45t-45 19H192q-26 0-45-19t-19-45V832q0-26 19-45t45-19h1408q26 0 45 19t19 45zm0-512v128q0 26-19 45t-45 19H192q-26 0-45-19t-19-45V320q0-26 19-45t45-19h1408q26 0 45 19t19 45z"></path></symbol>
<symbol id="fa-volume-off" viewBox="0 0 1792 1792"><title>Volume off</title><path d="M1280 352v1088q0 26-19 45t-45 19-45-19l-333-333H576q-26 0-45-19t-19-45V704q0-26 19-45t45-19h262l333-333q19-19 45-19t45 19 19 45z"></path></symbol>
<symbol id="fa-ban" viewBox="0 0 1792 1792"><title>Ban</title><path d="M1440 893q0-161-87-295l-754 753q137 89 297 89 111 0 211.5-43.5T1281 1280t116-174.5 43-212.5zm-999 299l755-754q-135-91-300-91-148 0-273 73T425 619t-73 274q0 162 89 299zm1223-299q0 157-61 300t-163.5 246-245 164-298.5 61-298.5-61-245-164T189 1193t-61-300 61-299.5T352.5 348t245-164T896 123t298.5 61 245 164T1603 593.5t61 299.5z"></path></symbol>
</svg><!-- end insert svg here --> </svg><!-- end insert svg here -->
</svg> </svg>
<!-- The application will be rendered inside this element, <!-- The application will be rendered inside this element,