add lists support
This commit is contained in:
parent
39439f5f9d
commit
1d25fa641e
|
@ -22,4 +22,5 @@ module.exports = [
|
||||||
{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-thumbtack', 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'},
|
||||||
]
|
]
|
8
routes/_api/lists.js
Normal file
8
routes/_api/lists.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import { get } from '../_utils/ajax'
|
||||||
|
|
||||||
|
export function getLists(instanceName, accessToken) {
|
||||||
|
let url = `https://${instanceName}/api/v1/lists`
|
||||||
|
return get(url, {
|
||||||
|
'Authorization': `Bearer ${accessToken}`
|
||||||
|
})
|
||||||
|
}
|
|
@ -19,6 +19,8 @@ function getTimelineUrlPath(timeline) {
|
||||||
return 'statuses'
|
return 'statuses'
|
||||||
} else if (timeline.startsWith('account/')) {
|
} else if (timeline.startsWith('account/')) {
|
||||||
return 'accounts'
|
return 'accounts'
|
||||||
|
} else if (timeline.startsWith('list/')) {
|
||||||
|
return 'timelines/list'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +33,9 @@ export function getTimeline(instanceName, accessToken, timeline, maxId, since) {
|
||||||
} else if (timeline.startsWith('status/')) {
|
} else if (timeline.startsWith('status/')) {
|
||||||
url += '/' + timeline.split('/').slice(-1)[0] + '/context'
|
url += '/' + timeline.split('/').slice(-1)[0] + '/context'
|
||||||
} else if (timeline.startsWith('account/')) {
|
} else if (timeline.startsWith('account/')) {
|
||||||
url += '/' + timeline.split('/').slice(-1)[0] +'/statuses'
|
url += '/' + timeline.split('/').slice(-1)[0] + '/statuses'
|
||||||
|
} else if (timeline.startsWith('list/')) {
|
||||||
|
url += '/' + timeline.split('/').slice(-1)[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
let params = {}
|
let params = {}
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
<li>
|
<li>
|
||||||
<NavItem :page name="favorites" href="/favorites" svg="#fa-star" label="Favorites" />
|
<NavItem :page name="favorites" href="/favorites" svg="#fa-star" label="Favorites" />
|
||||||
</li>
|
</li>
|
||||||
|
{{elseif $pinnedPage.startsWith('/lists/')}}
|
||||||
|
<li>
|
||||||
|
<NavItem :page name="lists" href="{{$pinnedPage}}" svg="#fa-bars" label="{{$pinnedListTitle}}" />
|
||||||
|
</li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<li>
|
<li>
|
||||||
<NavItem :page name="community" href="/community" svg="#fa-comments" label="Community" />
|
<NavItem :page name="community" href="/community" svg="#fa-comments" label="Community" />
|
||||||
|
@ -60,8 +64,15 @@
|
||||||
<script>
|
<script>
|
||||||
import NavItem from './NavItem'
|
import NavItem from './NavItem'
|
||||||
import { store } from '../_store/store'
|
import { store } from '../_store/store'
|
||||||
|
import { fetchLists } from '../community/_actions/community'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
async oncreate() {
|
||||||
|
let pinnedPage = this.store.get('pinnedPage')
|
||||||
|
if (pinnedPage.startsWith('/lists')) {
|
||||||
|
await fetchLists()
|
||||||
|
}
|
||||||
|
},
|
||||||
store: () => store,
|
store: () => store,
|
||||||
components: {
|
components: {
|
||||||
NavItem
|
NavItem
|
||||||
|
|
|
@ -89,6 +89,8 @@
|
||||||
return 'Status context'
|
return 'Status context'
|
||||||
case 'account':
|
case 'account':
|
||||||
return `Account #${timelineValue} on ${$currentInstance}`
|
return `Account #${timelineValue} on ${$currentInstance}`
|
||||||
|
case 'list':
|
||||||
|
return `List #${timelineValue} on ${$currentInstance}`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
timelineType: (timeline) => {
|
timelineType: (timeline) => {
|
||||||
|
|
|
@ -176,6 +176,14 @@ export async function setInstanceInfo(instanceName, value) {
|
||||||
return await setMetaProperty(instanceName, 'instance', value)
|
return await setMetaProperty(instanceName, 'instance', value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getLists(instanceName) {
|
||||||
|
return await getMetaProperty(instanceName, 'lists')
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setLists(instanceName, value) {
|
||||||
|
return await setMetaProperty(instanceName, 'lists', value)
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// accounts/relationships
|
// accounts/relationships
|
||||||
//
|
//
|
||||||
|
|
|
@ -51,4 +51,24 @@ export function instanceComputations(store) {
|
||||||
'pinnedPage',
|
'pinnedPage',
|
||||||
['pinnedPages', 'currentInstance'],
|
['pinnedPages', 'currentInstance'],
|
||||||
(pinnedPages, currentInstance) => (currentInstance && pinnedPages[currentInstance]) || '/local')
|
(pinnedPages, currentInstance) => (currentInstance && pinnedPages[currentInstance]) || '/local')
|
||||||
|
|
||||||
|
store.compute(
|
||||||
|
'lists',
|
||||||
|
['instanceLists', 'currentInstance'],
|
||||||
|
(instanceLists, currentInstance) => (currentInstance && instanceLists[currentInstance]) || []
|
||||||
|
)
|
||||||
|
|
||||||
|
store.compute(
|
||||||
|
'pinnedListTitle',
|
||||||
|
['lists', 'pinnedPage'],
|
||||||
|
(lists, pinnedPage) => {
|
||||||
|
if (!pinnedPage.startsWith('/lists')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let listId = pinnedPage.split('/').slice(-1)[0]
|
||||||
|
let list = lists.find(_ => _.id === listId)
|
||||||
|
return list ? list.title : ''
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,9 +1,11 @@
|
||||||
import { updateVerifyCredentialsForInstance } from '../settings/instances/_actions/[instanceName]'
|
import { updateVerifyCredentialsForInstance } from '../settings/instances/_actions/[instanceName]'
|
||||||
|
import { fetchLists } from '../community/_actions/community'
|
||||||
|
|
||||||
export function observers(store) {
|
export function observers(store) {
|
||||||
store.observe('currentInstance', (currentInstance) => {
|
store.observe('currentInstance', (currentInstance) => {
|
||||||
if (currentInstance) {
|
if (currentInstance) {
|
||||||
updateVerifyCredentialsForInstance(currentInstance)
|
updateVerifyCredentialsForInstance(currentInstance)
|
||||||
|
fetchLists()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { observers } from './obsevers'
|
import { observers } from './observers'
|
||||||
import { computations } from './computations'
|
import { computations } from './computations'
|
||||||
import { mixins } from './mixins'
|
import { mixins } from './mixins'
|
||||||
import { LocalStorageStore } from './LocalStorageStore'
|
import { LocalStorageStore } from './LocalStorageStore'
|
||||||
|
@ -33,7 +33,8 @@ const store = new PinaforeStore({
|
||||||
sensitivesShown: {},
|
sensitivesShown: {},
|
||||||
autoplayGifs: false,
|
autoplayGifs: false,
|
||||||
markMediaAsSensitive: false,
|
markMediaAsSensitive: false,
|
||||||
pinnedPages: {}
|
pinnedPages: {},
|
||||||
|
instanceLists: {}
|
||||||
})
|
})
|
||||||
|
|
||||||
mixins(PinaforeStore)
|
mixins(PinaforeStore)
|
||||||
|
|
19
routes/community/_actions/community.js
Normal file
19
routes/community/_actions/community.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { store } from '../../_store/store'
|
||||||
|
import pAny from 'p-any'
|
||||||
|
import { database } from '../../_database/database'
|
||||||
|
import { getLists } from '../../_api/lists'
|
||||||
|
|
||||||
|
export async function fetchLists() {
|
||||||
|
let instanceName = store.get('currentInstance')
|
||||||
|
let accessToken = store.get('accessToken')
|
||||||
|
let lists = await pAny([
|
||||||
|
getLists(instanceName, accessToken).then(lists => {
|
||||||
|
/* no await */ database.setLists(instanceName, lists)
|
||||||
|
return lists
|
||||||
|
}),
|
||||||
|
database.getLists(instanceName)
|
||||||
|
])
|
||||||
|
let instanceLists = store.get('instanceLists')
|
||||||
|
instanceLists[instanceName] = lists
|
||||||
|
store.set({instanceLists: instanceLists})
|
||||||
|
}
|
|
@ -79,6 +79,7 @@
|
||||||
let href = this.get('href')
|
let href = this.get('href')
|
||||||
pinnedPages[currentInstance] = href
|
pinnedPages[currentInstance] = href
|
||||||
this.store.set({pinnedPages: pinnedPages})
|
this.store.set({pinnedPages: pinnedPages})
|
||||||
|
this.store.save()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,13 @@
|
||||||
label="Favorites"
|
label="Favorites"
|
||||||
icon="#fa-star"
|
icon="#fa-star"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{{#each $lists as list}}
|
||||||
|
<PageListItem href="/lists/{{list.id}}"
|
||||||
|
label="{{list.title}}"
|
||||||
|
icon="#fa-bars"
|
||||||
|
/>
|
||||||
|
{{/each}}
|
||||||
</PageList>
|
</PageList>
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
|
@ -47,8 +54,12 @@
|
||||||
import HiddenFromSSR from '../_components/HiddenFromSSR'
|
import HiddenFromSSR from '../_components/HiddenFromSSR'
|
||||||
import PageList from './_components/PageList.html'
|
import PageList from './_components/PageList.html'
|
||||||
import PageListItem from './_components/PageListItem.html'
|
import PageListItem from './_components/PageListItem.html'
|
||||||
|
import { fetchLists } from './_actions/community'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
async oncreate() {
|
||||||
|
await fetchLists()
|
||||||
|
},
|
||||||
store: () => store,
|
store: () => store,
|
||||||
components: {
|
components: {
|
||||||
Layout,
|
Layout,
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
|
|
||||||
<Layout page='favorites' virtual="true" virtualRealm="favorites">
|
<Layout page='favorites' virtual="true" virtualRealm="favorites">
|
||||||
{{#if $isUserLoggedIn}}
|
{{#if $isUserLoggedIn}}
|
||||||
<DynamicPageBanner title="Favorites" icon="#fa-star"/>
|
{{#if $pinnedPage !== '/favorites'}}
|
||||||
|
<DynamicPageBanner title="Favorites" icon="#fa-star"/>
|
||||||
|
{{/if}}
|
||||||
<LazyTimeline timeline='favorites' />
|
<LazyTimeline timeline='favorites' />
|
||||||
{{else}}
|
{{else}}
|
||||||
<HiddenFromSSR>
|
<HiddenFromSSR>
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
|
|
||||||
<Layout page='federated' virtual="true" virtualRealm="federated">
|
<Layout page='federated' virtual="true" virtualRealm="federated">
|
||||||
{{#if $isUserLoggedIn}}
|
{{#if $isUserLoggedIn}}
|
||||||
<DynamicPageBanner title="Federated Timeline" icon="#fa-globe"/>
|
{{#if $pinnedPage !== '/federated'}}
|
||||||
|
<DynamicPageBanner title="Federated Timeline" icon="#fa-globe"/>
|
||||||
|
{{/if}}
|
||||||
<LazyTimeline timeline='federated' />
|
<LazyTimeline timeline='federated' />
|
||||||
{{else}}
|
{{else}}
|
||||||
<HiddenFromSSR>
|
<HiddenFromSSR>
|
||||||
|
|
47
routes/lists/[listId].html
Normal file
47
routes/lists/[listId].html
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<:Head>
|
||||||
|
<title>Pinafore – {{listTitle}}</title>
|
||||||
|
</:Head>
|
||||||
|
|
||||||
|
<Layout page='lists' virtual="true" virtualRealm="list/{{params.listId}}">
|
||||||
|
{{#if $isUserLoggedIn}}
|
||||||
|
{{#if $pinnedPage !== `/lists/${params.listId}`}}
|
||||||
|
<DynamicPageBanner title="{{listTitle}}" icon="#fa-bars"/>
|
||||||
|
{{/if}}
|
||||||
|
<LazyTimeline timeline='list/{{params.listId}}' />
|
||||||
|
{{else}}
|
||||||
|
<HiddenFromSSR>
|
||||||
|
<FreeTextLayout>
|
||||||
|
<h1>List</h1>
|
||||||
|
|
||||||
|
<p>A list will appear here when logged in.</p>
|
||||||
|
</FreeTextLayout>
|
||||||
|
</HiddenFromSSR>
|
||||||
|
{{/if}}
|
||||||
|
</Layout>
|
||||||
|
<script>
|
||||||
|
import Layout from '../_components/Layout.html'
|
||||||
|
import LazyTimeline from '../_components/timeline/LazyTimeline.html'
|
||||||
|
import FreeTextLayout from '../_components/FreeTextLayout.html'
|
||||||
|
import { store } from '../_store/store.js'
|
||||||
|
import HiddenFromSSR from '../_components/HiddenFromSSR'
|
||||||
|
import DynamicPageBanner from '../_components/DynamicPageBanner.html'
|
||||||
|
import { fetchLists } from '../community/_actions/community'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
async oncreate() {
|
||||||
|
await fetchLists()
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
list: (params, $lists) => $lists && $lists.find(_ => _.id === params['listId']),
|
||||||
|
listTitle: (list) => list ? list.title : ''
|
||||||
|
},
|
||||||
|
store: () => store,
|
||||||
|
components: {
|
||||||
|
Layout,
|
||||||
|
LazyTimeline,
|
||||||
|
FreeTextLayout,
|
||||||
|
HiddenFromSSR,
|
||||||
|
DynamicPageBanner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -4,7 +4,9 @@
|
||||||
|
|
||||||
<Layout page='local' virtual="true" virtualRealm="local">
|
<Layout page='local' virtual="true" virtualRealm="local">
|
||||||
{{#if $isUserLoggedIn}}
|
{{#if $isUserLoggedIn}}
|
||||||
<DynamicPageBanner title="Local Timeline" icon="#fa-users"/>
|
{{#if $pinnedPage !== '/local'}}
|
||||||
|
<DynamicPageBanner title="Local Timeline" icon="#fa-users"/>
|
||||||
|
{{/if}}
|
||||||
<LazyTimeline timeline='local' />
|
<LazyTimeline timeline='local' />
|
||||||
{{else}}
|
{{else}}
|
||||||
<HiddenFromSSR>
|
<HiddenFromSSR>
|
||||||
|
|
|
@ -87,6 +87,7 @@ body.offline,body.theme-hotpants.offline,body.theme-majesty.offline,body.theme-o
|
||||||
<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-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-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>
|
||||||
</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,
|
||||||
|
|
Loading…
Reference in a new issue