feat: add account tab pages (#422)

zio/stable
Joaquín Sánchez 2022-12-13 22:01:25 +01:00 committed by GitHub
parent 8f8e65e9db
commit 089890677f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 134 additions and 43 deletions

View File

@ -0,0 +1,41 @@
<script setup lang="ts">
const { t } = useI18n()
const route = useRoute()
const server = $(computedEager(() => route.params.server as string))
const account = $(computedEager(() => route.params.account as string))
const tabs = $computed(() => [
{
name: 'account-index',
to: {
name: 'account-index',
params: { server, account },
},
display: t('tab.posts'),
icon: 'i-ri:file-list-2-line',
},
{
name: 'account-replies',
to: {
name: 'account-replies',
params: { server, account },
},
display: t('tab.posts_with_replies'),
icon: 'i-ri:chat-3-line',
},
{
name: 'account-media',
to: {
name: 'account-media',
params: { server, account },
},
display: t('tab.media'),
icon: 'i-ri:camera-2-line',
},
] as const)
</script>
<template>
<CommonRouteTabs force :options="tabs" prevent-scroll-top command />
</template>

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import type { RouteLocationRaw } from 'vue-router' import type { RouteLocationRaw } from 'vue-router'
const { options, command, replace } = $defineProps<{ const { options, command, replace, preventScrollTop = false } = $defineProps<{
options: { options: {
to: RouteLocationRaw to: RouteLocationRaw
display: string display: string
@ -10,6 +10,7 @@ const { options, command, replace } = $defineProps<{
}[] }[]
command?: boolean command?: boolean
replace?: boolean replace?: boolean
preventScrollTop?: boolean
}>() }>()
const router = useRouter() const router = useRouter()
@ -36,7 +37,7 @@ useCommands(() => command
tabindex="1" tabindex="1"
hover:bg-active transition-100 hover:bg-active transition-100
exact-active-class="children:(font-bold !border-primary !op100)" exact-active-class="children:(font-bold !border-primary !op100)"
@click="$scrollToTop" @click="!preventScrollTop && $scrollToTop()"
> >
<span ws-nowrap mxa sm:px2 sm:py3 py2 text-center border-b-3 op50 hover:op70 border-transparent>{{ option.display }}</span> <span ws-nowrap mxa sm:px2 sm:py3 py2 text-center border-b-3 op50 hover:op70 border-transparent>{{ option.display }}</span>
</NuxtLink> </NuxtLink>

View File

@ -8,6 +8,7 @@
"follow": "Follow", "follow": "Follow",
"follow_back": "Follow back", "follow_back": "Follow back",
"follow_requested": "Requested", "follow_requested": "Requested",
"followers": "Followers",
"followers_count": "{0} Followers", "followers_count": "{0} Followers",
"following": "Following", "following": "Following",
"following_count": "{0} Following", "following_count": "{0} Following",
@ -18,6 +19,7 @@
"muted_users": "Muted users", "muted_users": "Muted users",
"mutuals": "Mutuals", "mutuals": "Mutuals",
"pinned": "Pinned", "pinned": "Pinned",
"posts": "Posts",
"posts_count": "{0} Posts", "posts_count": "{0} Posts",
"profile_description": "{0}'s profile header", "profile_description": "{0}'s profile header",
"profile_unavailable": "Profile unavailable", "profile_unavailable": "Profile unavailable",

View File

@ -8,6 +8,7 @@
"follow": "Seguir", "follow": "Seguir",
"follow_back": "Seguir de vuelta", "follow_back": "Seguir de vuelta",
"follow_requested": "Enviado", "follow_requested": "Enviado",
"followers": "Seguidores",
"followers_count": "{0} Seguidores|{0} Seguidor|{0} Seguidores", "followers_count": "{0} Seguidores|{0} Seguidor|{0} Seguidores",
"following": "Siguiendo", "following": "Siguiendo",
"following_count": "{0} Siguiendo", "following_count": "{0} Siguiendo",
@ -18,6 +19,7 @@
"muted_users": "Usuarios silenciados", "muted_users": "Usuarios silenciados",
"mutuals": "Mutuo", "mutuals": "Mutuo",
"pinned": "Publicaciones fijadas", "pinned": "Publicaciones fijadas",
"posts": "Publicaciones",
"posts_count": "{0} publicaciones|{0} publicación|{0} publicaciones", "posts_count": "{0} publicaciones|{0} publicación|{0} publicaciones",
"profile_description": "Encabezado del perfil de {0}", "profile_description": "Encabezado del perfil de {0}",
"profile_unavailable": "Perfil no disponible", "profile_unavailable": "Perfil no disponible",
@ -172,7 +174,7 @@
"tab": { "tab": {
"for_you": "Para tí", "for_you": "Para tí",
"hashtags": "Etiquetas", "hashtags": "Etiquetas",
"media": "Medios de comunicación", "media": "Multimedia",
"news": "Noticias", "news": "Noticias",
"notifications_all": "Todas", "notifications_all": "Todas",
"notifications_mention": "Menciones", "notifications_mention": "Menciones",

View File

@ -11,12 +11,6 @@ const { t } = useI18n()
const { data: account, refresh } = $(await useAsyncData(() => fetchAccountByHandle(accountName).catch(() => null))) const { data: account, refresh } = $(await useAsyncData(() => fetchAccountByHandle(accountName).catch(() => null)))
const relationship = $computed(() => account ? useRelationship(account).value : undefined) const relationship = $computed(() => account ? useRelationship(account).value : undefined)
if (account) {
useHeadFixed({
title: () => `${getDisplayName(account)} (@${account.acct})`,
})
}
onReactivated(() => { onReactivated(() => {
// Silently update data when reentering the page // Silently update data when reentering the page
// The user will see the previous content first, and any changes will be updated to the UI when the request is completed // The user will see the previous content first, and any changes will be updated to the UI when the request is completed

View File

@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
const { t } = useI18n()
const params = useRoute().params const params = useRoute().params
const handle = $(computedEager(() => params.account as string)) const handle = $(computedEager(() => params.account as string))
@ -6,6 +7,12 @@ definePageMeta({ name: 'account-followers' })
const account = await fetchAccountByHandle(handle) const account = await fetchAccountByHandle(handle)
const paginator = account ? useMasto().accounts.iterateFollowers(account.id, {}) : null const paginator = account ? useMasto().accounts.iterateFollowers(account.id, {}) : null
if (account) {
useHeadFixed({
title: () => `${t('account.followers')} | ${getDisplayName(account)} (@${account})`,
})
}
</script> </script>
<template> <template>

View File

@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
const { t } = useI18n()
const params = useRoute().params const params = useRoute().params
const handle = $(computedEager(() => params.account as string)) const handle = $(computedEager(() => params.account as string))
@ -6,6 +7,12 @@ definePageMeta({ name: 'account-following' })
const account = await fetchAccountByHandle(handle) const account = await fetchAccountByHandle(handle)
const paginator = account ? useMasto().accounts.iterateFollowing(account.id, {}) : null const paginator = account ? useMasto().accounts.iterateFollowing(account.id, {}) : null
if (account) {
useHeadFixed({
title: () => `${t('account.following')} | ${getDisplayName(account)} (@${account})`,
})
}
</script> </script>
<template> <template>

View File

@ -1,52 +1,31 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Account } from 'masto' import type { Account } from 'masto'
import AccountTabs from '~/components/account/AccountTabs.vue'
const params = useRoute().params const params = useRoute().params
const handle = $(computedEager(() => params.account as string)) const handle = $(computedEager(() => params.account as string))
definePageMeta({ name: 'account-index' }) definePageMeta({ name: 'account-index' })
const { data: account } = await useAsyncData(`account:${handle}`, async () => (
window.history.state?.account as Account | undefined)
?? await fetchAccountByHandle(handle),
)
const { t } = useI18n() const { t } = useI18n()
const paginatorPosts = useMasto().accounts.iterateStatuses(account.value!.id, { excludeReplies: true }) const { data: account } = await useAsyncData(`account:${handle}`, async () => (
const paginatorPostsWithReply = useMasto().accounts.iterateStatuses(account.value!.id, { excludeReplies: false }) window.history.state?.account as Account | undefined)
const paginatorMedia = useMasto().accounts.iterateStatuses(account.value!.id, { onlyMedia: true, excludeReplies: false }) ?? await fetchAccountByHandle(handle),
)
const tabs = $computed(() => [ const paginator = useMasto().accounts.iterateStatuses(account.value!.id, { excludeReplies: true })
{
name: 'posts',
display: t('tab.posts'),
icon: 'i-ri:file-list-2-line',
paginator: paginatorPosts,
},
{
name: 'relies',
display: t('tab.posts_with_replies'),
icon: 'i-ri:chat-3-line',
paginator: paginatorPostsWithReply,
},
{
name: 'media',
display: t('tab.media'),
icon: 'i-ri:camera-2-line',
paginator: paginatorMedia,
},
] as const)
// Don't use local storage because it is better to default to Posts every time you visit a user's profile. if (account) {
const tab = $ref(tabs[0].name) useHeadFixed({
const paginator = $computed(() => tabs.find(t => t.name === tab)!.paginator) title: () => `${t('account.posts')} | ${getDisplayName(account.value!)} (@${account.value!.acct})`,
})
}
</script> </script>
<template> <template>
<div> <div>
<CommonTabs v-model="tab" :options="tabs" command /> <AccountTabs />
<KeepAlive> <TimelinePaginator :paginator="paginator" context="account" />
<TimelinePaginator :key="tab" :paginator="paginator" context="account" />
</KeepAlive>
</div> </div>
</template> </template>

View File

@ -0,0 +1,29 @@
<script setup lang="ts">
import type { Account } from 'masto'
definePageMeta({ name: 'account-media' })
const { t } = useI18n()
const params = useRoute().params
const handle = $(computedEager(() => params.account as string))
const { data: account } = await useAsyncData(`account:${handle}`, async () => (
window.history.state?.account as Account | undefined)
?? await fetchAccountByHandle(handle),
)
const paginator = useMasto().accounts.iterateStatuses(account.value!.id, { onlyMedia: true, excludeReplies: false })
if (account) {
useHeadFixed({
title: () => `${t('tab.media')} | ${getDisplayName(account.value!)} (@${account.value!.acct})`,
})
}
</script>
<template>
<div>
<AccountTabs />
<TimelinePaginator :paginator="paginator" context="account" />
</div>
</template>

View File

@ -0,0 +1,29 @@
<script setup lang="ts">
import type { Account } from 'masto'
definePageMeta({ name: 'account-replies' })
const { t } = useI18n()
const params = useRoute().params
const handle = $(computedEager(() => params.account as string))
const { data: account } = await useAsyncData(`account:${handle}`, async () => (
window.history.state?.account as Account | undefined)
?? await fetchAccountByHandle(handle),
)
const paginator = useMasto().accounts.iterateStatuses(account.value!.id, { excludeReplies: false })
if (account) {
useHeadFixed({
title: () => `${t('tab.posts_with_replies')} | ${getDisplayName(account.value!)} (@${account.value!.acct})`,
})
}
</script>
<template>
<div>
<AccountTabs />
<TimelinePaginator :paginator="paginator" context="account" />
</div>
</template>