more work on profile page
This commit is contained in:
parent
5e7438cb52
commit
88d59678f2
|
@ -1,20 +1,26 @@
|
|||
<div class="account-profile {{headerIsMissing ? 'header-is-missing' : ''}}" style="background-image: url({{profile.header}});">
|
||||
<div class="account-profile-grid">
|
||||
<div class="account-profile-avatar">
|
||||
<img src="{{profile.avatar}}">
|
||||
<img src="{{profile.avatar}}" aria-hidden="true">
|
||||
</div>
|
||||
<div class="account-profile-name">
|
||||
{{profile.display_name}}
|
||||
</div>
|
||||
<div class="account-profile-following">
|
||||
<div class="account-profile-followed-by">
|
||||
{{#if relationship && relationship.followed_by}}
|
||||
<span>
|
||||
Follows you
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="account-profile-follow">
|
||||
<svg>
|
||||
<use xlink:href="#fa-user-plus" />
|
||||
</svg>
|
||||
{{#if verifyCredentials && relationship && verifyCredentials.id !== relationship.id}}
|
||||
<IconButton
|
||||
label="{{relationship && relationship.following ? 'Unfollow' : 'Follow'}}"
|
||||
href="{{relationship && relationship.following ? '#fa-user-times' : '#fa-user-plus'}}"
|
||||
big="true"
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="account-profile-note">
|
||||
{{{profile.note}}}
|
||||
|
@ -32,6 +38,7 @@
|
|||
|
||||
.account-profile.header-is-missing {
|
||||
padding-top: 0;
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
||||
.account-profile-background {
|
||||
|
@ -45,7 +52,7 @@
|
|||
|
||||
.account-profile-grid {
|
||||
display: grid;
|
||||
grid-template-areas: "avatar name following follow"
|
||||
grid-template-areas: "avatar name followed-by follow"
|
||||
"avatar note note note";
|
||||
grid-template-columns: min-content auto 1fr min-content;
|
||||
grid-column-gap: 10px;
|
||||
|
@ -68,19 +75,19 @@
|
|||
}
|
||||
}
|
||||
|
||||
.account-profile-following, .account-profile-avatar, .account-profile-follow,
|
||||
.account-profile-followed-by, .account-profile-avatar, .account-profile-follow,
|
||||
.account-profile-name, .account-profile-username, .account-profile-note {
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.account-profile-following {
|
||||
grid-area: following;
|
||||
.account-profile-followed-by {
|
||||
grid-area: followed-by;
|
||||
align-self: center;
|
||||
text-transform: uppercase;
|
||||
color: var(--deemphasized-text-color);
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.account-profile-following span {
|
||||
.account-profile-followed-by span {
|
||||
background: rgba(30, 30, 30, 0.2);
|
||||
border-radius: 4px;
|
||||
padding: 3px 5px;
|
||||
|
@ -99,11 +106,6 @@
|
|||
grid-area: follow;
|
||||
align-self: center;
|
||||
}
|
||||
.account-profile-follow svg {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
fill: var(--svg-fill);
|
||||
}
|
||||
.account-profile-name {
|
||||
grid-area: name;
|
||||
font-size: 1.5em;
|
||||
|
@ -121,9 +123,14 @@
|
|||
}
|
||||
</style>
|
||||
<script>
|
||||
import IconButton from './IconButton.html'
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
headerIsMissing: (profile) => profile.header.endsWith('missing.png')
|
||||
},
|
||||
components: {
|
||||
IconButton
|
||||
}
|
||||
}
|
||||
</script>
|
56
routes/_components/IconButton.html
Normal file
56
routes/_components/IconButton.html
Normal file
|
@ -0,0 +1,56 @@
|
|||
{{#if pressable}}
|
||||
<button type="button"
|
||||
aria-label="{{label}}"
|
||||
aria-pressed="{{!!pressed}}"
|
||||
class="icon-button {{pressed ? 'pressed' : ''}} {{big ? 'big-icon' : ''}}">
|
||||
<svg>
|
||||
<use xlink:href="{{href}}" />
|
||||
</svg>
|
||||
</button>
|
||||
{{else}}
|
||||
<button type="button"
|
||||
aria-label="{{label}}"
|
||||
class="icon-button {{big ? 'big-icon' : ''}}">
|
||||
<svg>
|
||||
<use xlink:href="{{href}}" />
|
||||
</svg>
|
||||
</button>
|
||||
{{/if}}
|
||||
<style>
|
||||
button.icon-button {
|
||||
padding: 6px 10px;
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
button.icon-button svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
fill: var(--action-button-fill-color);
|
||||
}
|
||||
|
||||
button.icon-button.big-icon svg {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
button.icon-button:hover svg {
|
||||
fill: var(--action-button-fill-color-hover);
|
||||
}
|
||||
|
||||
button.icon-button:active svg {
|
||||
fill: var(--action-button-fill-color-active);
|
||||
}
|
||||
|
||||
button.icon-button.pressed svg {
|
||||
fill: var(--action-button-fill-color-pressed)
|
||||
}
|
||||
|
||||
button.icon-button.pressed:hover svg {
|
||||
fill: var(--action-button-fill-color-pressed-hover);
|
||||
}
|
||||
|
||||
button.icon-button.pressed:active svg {
|
||||
fill: var(--action-button-fill-color-pressed-active);
|
||||
}
|
||||
</style>
|
|
@ -1,30 +1,24 @@
|
|||
<div class="status-toolbar">
|
||||
<button aria-label="Reply" type="button">
|
||||
<svg>
|
||||
<use xlink:href="#fa-reply" />
|
||||
</svg>
|
||||
</button>
|
||||
<button aria-label="Boost" aria-pressed="{{status.reblogged}}" class="{{status.reblogged ? 'selected' : ''}}" type="button">
|
||||
<svg>
|
||||
{{#if status.visibility === 'private'}}
|
||||
<use xlink:href="#fa-lock" />
|
||||
{{elseif status.visibility === 'direct'}}
|
||||
<use xlink:href="#fa-envelope" />
|
||||
{{else}}
|
||||
<use xlink:href="#fa-retweet" />
|
||||
{{/if}}
|
||||
</svg>
|
||||
</button>
|
||||
<button aria-label="Favorite" aria-pressed="{{status.favourited}}" class="{{status.favourited ? 'selected' : ''}}" type="button">
|
||||
<svg>
|
||||
<use xlink:href="#fa-star" />
|
||||
</svg>
|
||||
</button>
|
||||
<button aria-label="Show more actions" type="button">
|
||||
<svg>
|
||||
<use xlink:href="#fa-ellipsis-h" />
|
||||
</svg>
|
||||
</button>
|
||||
<IconButton
|
||||
label="Reply"
|
||||
href="#fa-reply"
|
||||
/>
|
||||
<IconButton
|
||||
label="Boost"
|
||||
pressable="true"
|
||||
pressed="{{status.reblogged}}"
|
||||
href="{{status.visibility === 'private' ? '#fa-lock' : status.visibility === 'direct' ? '#fa-envelope' : '#fa-retweet'}}"
|
||||
/>
|
||||
<IconButton
|
||||
label="Favorite"
|
||||
pressable="true"
|
||||
pressed="{{status.favourited}}"
|
||||
href="#fa-star"
|
||||
/>
|
||||
<IconButton
|
||||
label="Show more actions"
|
||||
href="#fa-ellipsis-h"
|
||||
/>
|
||||
</div>
|
||||
<style>
|
||||
.status-toolbar {
|
||||
|
@ -32,41 +26,14 @@
|
|||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.status-toolbar button {
|
||||
padding: 6px 10px;
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.status-toolbar button svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
fill: var(--action-button-fill-color);
|
||||
}
|
||||
|
||||
.status-toolbar button:hover svg {
|
||||
fill: var(--action-button-fill-color-hover);
|
||||
}
|
||||
|
||||
.status-toolbar button:active svg {
|
||||
fill: var(--action-button-fill-color-active);
|
||||
}
|
||||
|
||||
.status-toolbar button.selected svg {
|
||||
fill: var(--action-button-fill-color-pressed)
|
||||
}
|
||||
|
||||
.status-toolbar button.selected:hover svg {
|
||||
fill: var(--action-button-fill-color-pressed-hover);
|
||||
}
|
||||
|
||||
.status-toolbar button.selected:active svg {
|
||||
fill: var(--action-button-fill-color-pressed-active);
|
||||
}
|
||||
|
||||
</style>
|
||||
<script>
|
||||
|
||||
import IconButton from '../IconButton.html'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
IconButton
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -1,10 +1,10 @@
|
|||
<div class="lazy-timeline">
|
||||
{{#if !$initialized}}
|
||||
<div transition:fade>
|
||||
<!-- <div transition:fade> -->
|
||||
<div class="loading-page">
|
||||
<LoadingSpinner />
|
||||
</div>
|
||||
</div>
|
||||
<!-- </div> -->
|
||||
{{/if}}
|
||||
{{#await promise}}
|
||||
{{then constructor}}
|
||||
|
@ -33,7 +33,8 @@
|
|||
<script>
|
||||
import { importTimeline } from '../../_utils/asyncModules'
|
||||
import LoadingSpinner from '../LoadingSpinner.html'
|
||||
import { fade } from 'svelte-transitions'
|
||||
// TODO: the transition seems to occasionally cause an error in Svelte, transition_run is undefined
|
||||
//import { fade } from 'svelte-transitions'
|
||||
import { store } from '../../_utils/store'
|
||||
|
||||
export default {
|
||||
|
@ -49,9 +50,9 @@
|
|||
}),
|
||||
components: {
|
||||
LoadingSpinner
|
||||
},
|
||||
}/*,
|
||||
transitions: {
|
||||
fade
|
||||
}
|
||||
}*/
|
||||
}
|
||||
</script>
|
61
routes/_utils/database/cache.js
Normal file
61
routes/_utils/database/cache.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
import QuickLRU from 'quick-lru'
|
||||
|
||||
export const statusesCache = {
|
||||
maxSize: 100,
|
||||
caches: {}
|
||||
}
|
||||
export const accountsCache = {
|
||||
maxSize: 50,
|
||||
caches: {}
|
||||
}
|
||||
export const relationshipsCache = {
|
||||
maxSize: 20,
|
||||
caches: {}
|
||||
}
|
||||
export const metaCache = {
|
||||
maxSize: 20,
|
||||
caches: {}
|
||||
}
|
||||
|
||||
if (process.browser && process.env.NODE_ENV !== 'production') {
|
||||
window.cacheStats = {
|
||||
statuses: statusesCache,
|
||||
accounts: accountsCache,
|
||||
relationships: relationshipsCache,
|
||||
meta: metaCache
|
||||
}
|
||||
}
|
||||
|
||||
function getOrCreateInstanceCache(cache, instanceName) {
|
||||
let cached = cache.caches[instanceName]
|
||||
if (!cached) {
|
||||
cached = cache.caches[instanceName] = new QuickLRU({maxSize: cache.maxSize})
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
export function clearCache(cache, instanceName) {
|
||||
delete cache.caches[instanceName]
|
||||
}
|
||||
export function setInCache(cache, instanceName, key, value) {
|
||||
let instanceCache = getOrCreateInstanceCache(cache, instanceName)
|
||||
return instanceCache.set(key, value)
|
||||
}
|
||||
|
||||
export function getInCache(cache, instanceName, key) {
|
||||
let instanceCache = getOrCreateInstanceCache(cache, instanceName)
|
||||
return instanceCache.get(key)
|
||||
}
|
||||
|
||||
export function hasInCache(cache, instanceName, key) {
|
||||
let instanceCache = getOrCreateInstanceCache(cache, instanceName)
|
||||
let res = instanceCache.has(key)
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (res) {
|
||||
cache.hits = (cache.hits || 0) + 1
|
||||
} else {
|
||||
cache.misses = (cache.misses || 0) + 1
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
export const STATUSES_STORE = 'statuses'
|
||||
export const TIMELINE_STORE = 'timelines'
|
||||
export const META_STORE = 'meta'
|
||||
export const ACCOUNTS_STORE= 'accounts'
|
||||
export const ACCOUNTS_STORE = 'accounts'
|
||||
export const RELATIONSHIPS_STORE = 'relationships'
|
|
@ -10,69 +10,44 @@ import {
|
|||
import {
|
||||
META_STORE,
|
||||
TIMELINE_STORE,
|
||||
STATUSES_STORE, ACCOUNTS_STORE
|
||||
STATUSES_STORE,
|
||||
ACCOUNTS_STORE,
|
||||
RELATIONSHIPS_STORE
|
||||
} from './constants'
|
||||
|
||||
import QuickLRU from 'quick-lru'
|
||||
import {
|
||||
statusesCache,
|
||||
relationshipsCache,
|
||||
accountsCache,
|
||||
metaCache,
|
||||
clearCache,
|
||||
getInCache,
|
||||
hasInCache,
|
||||
setInCache
|
||||
} from './cache'
|
||||
|
||||
const statusesCache = {
|
||||
maxSize: 100,
|
||||
caches: {}
|
||||
}
|
||||
const accountsCache = {
|
||||
maxSize: 50,
|
||||
caches: {}
|
||||
}
|
||||
const metaCache = {
|
||||
maxSize: 20,
|
||||
caches: {}
|
||||
}
|
||||
//
|
||||
// helpers
|
||||
//
|
||||
|
||||
if (process.browser && process.env.NODE_ENV !== 'production') {
|
||||
window.cacheStats = {
|
||||
statuses: {
|
||||
cache: statusesCache,
|
||||
hits: 0,
|
||||
misses: 0
|
||||
},
|
||||
accounts: {
|
||||
cache: accountsCache,
|
||||
hits: 0,
|
||||
misses: 0
|
||||
},
|
||||
meta: {
|
||||
cache: accountsCache,
|
||||
hits: 0,
|
||||
misses: 0
|
||||
}
|
||||
async function getGenericEntityWithId(store, cache, instanceName, id) {
|
||||
if (hasInCache(cache, instanceName, id)) {
|
||||
return getInCache(cache, instanceName, id)
|
||||
}
|
||||
const db = await getDatabase(instanceName)
|
||||
let result = await dbPromise(db, store, 'readonly', (store, callback) => {
|
||||
store.get(id).onsuccess = (e) => callback(e.target.result)
|
||||
})
|
||||
setInCache(cache, instanceName, id, result)
|
||||
return result
|
||||
}
|
||||
|
||||
function clearCache(cache, instanceName) {
|
||||
delete cache.caches[instanceName]
|
||||
}
|
||||
|
||||
function getOrCreateInstanceCache(cache, instanceName) {
|
||||
let cached = cache.caches[instanceName]
|
||||
if (!cached) {
|
||||
cached = cache.caches[instanceName] = new QuickLRU({maxSize: cache.maxSize})
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
function setInCache(cache, instanceName, key, value) {
|
||||
let instanceCache = getOrCreateInstanceCache(cache, instanceName)
|
||||
return instanceCache.set(key, value)
|
||||
}
|
||||
|
||||
function getInCache(cache, instanceName, key) {
|
||||
let instanceCache = getOrCreateInstanceCache(cache, instanceName)
|
||||
return instanceCache.get(key)
|
||||
}
|
||||
|
||||
function hasInCache(cache, instanceName, key) {
|
||||
let instanceCache = getOrCreateInstanceCache(cache, instanceName)
|
||||
return instanceCache.has(key)
|
||||
async function setGenericEntityWithId(store, cache, instanceName, entity) {
|
||||
setInCache(cache, instanceName, entity.id, entity)
|
||||
const db = await getDatabase(instanceName)
|
||||
return await dbPromise(db, store, 'readwrite', (store) => {
|
||||
store.put(entity)
|
||||
})
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -129,23 +104,7 @@ export async function insertStatuses(instanceName, timeline, statuses) {
|
|||
}
|
||||
|
||||
export async function getStatus(instanceName, statusId) {
|
||||
if (hasInCache(statusesCache, instanceName, statusId)) {
|
||||
if (process.browser && process.env.NODE_ENV !== 'production') {
|
||||
window.cacheStats.statuses.hits++
|
||||
}
|
||||
return getInCache(statusesCache, instanceName, statusId)
|
||||
}
|
||||
const db = await getDatabase(instanceName)
|
||||
let result = await dbPromise(db, STATUSES_STORE, 'readonly', (store, callback) => {
|
||||
store.get(statusId).onsuccess = (e) => {
|
||||
callback(e.target.result && e.target.result)
|
||||
}
|
||||
})
|
||||
setInCache(statusesCache, instanceName, statusId, result)
|
||||
if (process.browser && process.env.NODE_ENV !== 'production') {
|
||||
window.cacheStats.statuses.misses++
|
||||
}
|
||||
return result
|
||||
return await getGenericEntityWithId(STATUSES_STORE, statusesCache, instanceName, statusId)
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -154,9 +113,6 @@ export async function getStatus(instanceName, statusId) {
|
|||
|
||||
async function getMetaProperty(instanceName, key) {
|
||||
if (hasInCache(metaCache, instanceName, key)) {
|
||||
if (process.browser && process.env.NODE_ENV !== 'production') {
|
||||
window.cacheStats.meta.hits++
|
||||
}
|
||||
return getInCache(metaCache, instanceName, key)
|
||||
}
|
||||
const db = await getDatabase(instanceName)
|
||||
|
@ -166,9 +122,6 @@ async function getMetaProperty(instanceName, key) {
|
|||
}
|
||||
})
|
||||
setInCache(metaCache, instanceName, key, result)
|
||||
if (process.browser && process.env.NODE_ENV !== 'production') {
|
||||
window.cacheStats.meta.misses++
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
@ -200,34 +153,23 @@ export async function setInstanceInfo(instanceName, value) {
|
|||
}
|
||||
|
||||
//
|
||||
// accounts
|
||||
// accounts/relationships
|
||||
//
|
||||
|
||||
export async function getAccount(instanceName, accountId) {
|
||||
if (hasInCache(accountsCache, instanceName, accountId)) {
|
||||
if (process.browser && process.env.NODE_ENV !== 'production') {
|
||||
window.cacheStats.accounts.hits++
|
||||
}
|
||||
return getInCache(accountsCache, instanceName, accountId)
|
||||
}
|
||||
const db = await getDatabase(instanceName)
|
||||
let result = await dbPromise(db, ACCOUNTS_STORE, 'readonly', (store, callback) => {
|
||||
store.get(accountId).onsuccess = (e) => {
|
||||
callback(e.target.result && e.target.result)
|
||||
}
|
||||
})
|
||||
if (process.browser && process.env.NODE_ENV !== 'production') {
|
||||
window.cacheStats.accounts.misses++
|
||||
}
|
||||
return result
|
||||
return await getGenericEntityWithId(ACCOUNTS_STORE, accountsCache, instanceName, accountId)
|
||||
}
|
||||
|
||||
export async function setAccount(instanceName, account) {
|
||||
setInCache(accountsCache, instanceName, account.id, account)
|
||||
const db = await getDatabase(instanceName)
|
||||
return await dbPromise(db, ACCOUNTS_STORE, 'readwrite', (store) => {
|
||||
store.put(account)
|
||||
})
|
||||
return await setGenericEntityWithId(ACCOUNTS_STORE, accountsCache, instanceName, account)
|
||||
}
|
||||
|
||||
export async function getRelationship(instanceName, accountId) {
|
||||
return await getGenericEntityWithId(RELATIONSHIPS_STORE, relationshipsCache, instanceName, accountId)
|
||||
}
|
||||
|
||||
export async function setRelationship(instanceName, relationship) {
|
||||
return await setGenericEntityWithId(RELATIONSHIPS_STORE, relationshipsCache, instanceName, relationship)
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
const openReqs = {}
|
||||
const databaseCache = {}
|
||||
|
||||
const DB_VERSION = 2
|
||||
|
||||
import {
|
||||
META_STORE,
|
||||
TIMELINE_STORE,
|
||||
STATUSES_STORE,
|
||||
ACCOUNTS_STORE
|
||||
ACCOUNTS_STORE,
|
||||
RELATIONSHIPS_STORE
|
||||
} from './constants'
|
||||
|
||||
export function getDatabase(instanceName) {
|
||||
|
@ -17,19 +20,24 @@ export function getDatabase(instanceName) {
|
|||
}
|
||||
|
||||
databaseCache[instanceName] = new Promise((resolve, reject) => {
|
||||
let req = indexedDB.open(instanceName, 1)
|
||||
let req = indexedDB.open(instanceName, DB_VERSION)
|
||||
openReqs[instanceName] = req
|
||||
req.onerror = reject
|
||||
req.onblocked = () => {
|
||||
console.log('idb blocked')
|
||||
}
|
||||
req.onupgradeneeded = () => {
|
||||
req.onupgradeneeded = (e) => {
|
||||
let db = req.result;
|
||||
db.createObjectStore(META_STORE, {keyPath: 'key'})
|
||||
db.createObjectStore(STATUSES_STORE, {keyPath: 'id'})
|
||||
db.createObjectStore(ACCOUNTS_STORE, {keyPath: 'id'})
|
||||
let timelineStore = db.createObjectStore(TIMELINE_STORE, {keyPath: 'id'})
|
||||
timelineStore.createIndex('statusId', 'statusId')
|
||||
if (e.oldVersion < 1) {
|
||||
db.createObjectStore(META_STORE, {keyPath: 'key'})
|
||||
db.createObjectStore(STATUSES_STORE, {keyPath: 'id'})
|
||||
db.createObjectStore(ACCOUNTS_STORE, {keyPath: 'id'})
|
||||
let timelineStore = db.createObjectStore(TIMELINE_STORE, {keyPath: 'id'})
|
||||
timelineStore.createIndex('statusId', 'statusId')
|
||||
}
|
||||
if (e.oldVersion < 2) {
|
||||
db.createObjectStore(RELATIONSHIPS_STORE, {keyPath: 'id'})
|
||||
}
|
||||
}
|
||||
req.onsuccess = () => resolve(req.result)
|
||||
})
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { get } from '../ajax'
|
||||
import { get, paramsString } from '../ajax'
|
||||
import { basename } from './utils'
|
||||
|
||||
export function getVerifyCredentials(instanceName, accessToken) {
|
||||
|
@ -13,4 +13,13 @@ export function getAccount(instanceName, accessToken, accountId) {
|
|||
return get(url, {
|
||||
'Authorization': `Bearer ${accessToken}`
|
||||
})
|
||||
}
|
||||
|
||||
export async function getRelationship(instanceName, accessToken, accountId) {
|
||||
let url = `${basename(instanceName)}/api/v1/accounts/relationships`
|
||||
url += '?' + paramsString({id: accountId})
|
||||
let res = await get(url, {
|
||||
'Authorization': `Bearer ${accessToken}`
|
||||
})
|
||||
return res[0]
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import { Store } from 'svelte/store.js'
|
||||
import { storeObservers } from './storeObservers'
|
||||
|
||||
const LOCAL_STORAGE_KEYS = new Set([
|
||||
"currentInstance",
|
||||
|
@ -112,6 +113,12 @@ store.compute(
|
|||
}
|
||||
)
|
||||
|
||||
store.compute(
|
||||
'currentVerifyCredentials',
|
||||
['currentInstance', 'verifyCredentials'],
|
||||
(currentInstance, verifyCredentials) => verifyCredentials && verifyCredentials[currentInstance]
|
||||
)
|
||||
|
||||
store.compute('currentTimelineData', ['currentInstance', 'currentTimeline', 'timelines'],
|
||||
(currentInstance, currentTimeline, timelines) => {
|
||||
return ((timelines && timelines[currentInstance]) || {})[currentTimeline] || {}
|
||||
|
@ -122,6 +129,8 @@ store.compute('runningUpdate', ['currentTimelineData'], (currentTimelineData) =>
|
|||
store.compute('initialized', ['currentTimelineData'], (currentTimelineData) => currentTimelineData.initialized)
|
||||
store.compute('lastStatusId', ['statusIds'], (statusIds) => statusIds.length && statusIds[statusIds.length - 1])
|
||||
|
||||
storeObservers(store)
|
||||
|
||||
if (process.browser && process.env.NODE_ENV !== 'production') {
|
||||
window.store = store // for debugging
|
||||
}
|
||||
|
|
7
routes/_utils/storeObservers.js
Normal file
7
routes/_utils/storeObservers.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { updateVerifyCredentialsForInstance } from '../settings/instances/_actions/[instanceName]'
|
||||
|
||||
export function storeObservers(store) {
|
||||
store.observe('currentInstance', (currentInstance) => {
|
||||
updateVerifyCredentialsForInstance(currentInstance)
|
||||
})
|
||||
}
|
|
@ -12,7 +12,10 @@
|
|||
{{#if $isUserLoggedIn}}
|
||||
<DynamicPageBanner title="{{profileName}}" />
|
||||
{{#if $currentAccountProfile}}
|
||||
<AccountProfile profile="{{$currentAccountProfile}}" />
|
||||
<AccountProfile profile="{{$currentAccountProfile}}"
|
||||
relationship="{{$currentAccountRelationship}}"
|
||||
verifyCredentials="{{$currentVerifyCredentials}}"
|
||||
/>
|
||||
{{/if}}
|
||||
<LazyTimeline timeline='account/{{params.accountId}}' />
|
||||
{{else}}
|
||||
|
@ -32,13 +35,16 @@
|
|||
import { store } from '../_utils/store.js'
|
||||
import HiddenFromSSR from '../_components/HiddenFromSSR'
|
||||
import DynamicPageBanner from '../_components/DynamicPageBanner.html'
|
||||
import { showAccountProfile } from './_actions/[accountId]'
|
||||
import { updateProfileAndRelationship } from './_actions/[accountId]'
|
||||
import AccountProfile from '../_components/AccountProfile.html'
|
||||
import { updateVerifyCredentialsForInstance } from '../settings/instances/_actions/[instanceName]'
|
||||
|
||||
export default {
|
||||
oncreate() {
|
||||
let accountId = this.get('params').accountId
|
||||
showAccountProfile(accountId)
|
||||
let instanceName = this.store.get('currentInstance')
|
||||
updateProfileAndRelationship(accountId)
|
||||
updateVerifyCredentialsForInstance(instanceName)
|
||||
},
|
||||
store: () => store,
|
||||
computed: {
|
||||
|
|
|
@ -1,24 +1,54 @@
|
|||
import { getAccount } from '../../_utils/mastodon/user'
|
||||
import { getAccount, getRelationship } from '../../_utils/mastodon/user'
|
||||
import { database } from '../../_utils/database/database'
|
||||
import { store } from '../../_utils/store'
|
||||
|
||||
export async function showAccountProfile(accountId) {
|
||||
store.set({currentAccountProfile: null})
|
||||
let instanceName = store.get('currentInstance')
|
||||
let accessToken = store.get('accessToken')
|
||||
|
||||
async function updateAccount(accountId, instanceName, accessToken) {
|
||||
let localPromise = database.getAccount(instanceName, accountId)
|
||||
let remotePromise = getAccount(instanceName, accessToken, accountId).then(account => {
|
||||
database.setAccount(instanceName, account)
|
||||
return account
|
||||
})
|
||||
|
||||
let localAccount = await localPromise
|
||||
store.set({currentAccountProfile: localAccount})
|
||||
try {
|
||||
let remoteAccount = await remotePromise
|
||||
store.set({currentAccountProfile: remoteAccount})
|
||||
store.set({currentAccountProfile: (await localPromise)})
|
||||
} catch (e) {
|
||||
console.error("couldn't fetch profile", e)
|
||||
console.error(e)
|
||||
}
|
||||
try {
|
||||
store.set({currentAccountProfile: (await remotePromise)})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
async function updateRelationship(accountId, instanceName, accessToken) {
|
||||
let localPromise = database.getRelationship(instanceName, accountId)
|
||||
let remotePromise = getRelationship(instanceName, accessToken, accountId).then(relationship => {
|
||||
database.setRelationship(instanceName, relationship)
|
||||
return relationship
|
||||
})
|
||||
try {
|
||||
store.set({currentAccountRelationship: (await localPromise)})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
try {
|
||||
store.set({currentAccountRelationship: (await remotePromise)})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateProfileAndRelationship(accountId) {
|
||||
store.set({
|
||||
currentAccountProfile: null,
|
||||
currentAccountRelationship: null
|
||||
})
|
||||
let instanceName = store.get('currentInstance')
|
||||
let accessToken = store.get('accessToken')
|
||||
|
||||
await Promise.all([
|
||||
updateAccount(accountId, instanceName, accessToken),
|
||||
updateRelationship(accountId, instanceName, accessToken)
|
||||
])
|
||||
}
|
|
@ -63,5 +63,5 @@
|
|||
--deemphasized-text-color: #666;
|
||||
--focus-outline: $focus-outline;
|
||||
|
||||
--status-direct-background: darken($body-bg-color, 5%)
|
||||
--status-direct-background: darken($body-bg-color, 5%);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue