Browse Source

refactor(auth): replace 'pending' with 'initialized' in auth session and update loading states across components

main
npmrun 9 hours ago
parent
commit
0540db2c8d
  1. 6
      app/components/AppShell.vue
  2. 4
      app/components/PostComments.vue
  3. 25
      app/layouts/public.vue
  4. 4
      app/pages/@[publicSlug]/about/index.vue
  5. 4
      app/pages/@[publicSlug]/index.vue
  6. 4
      app/pages/@[publicSlug]/posts/[postSlug].vue
  7. 4
      app/pages/@[publicSlug]/posts/index.vue
  8. 4
      app/pages/@[publicSlug]/reading/index.vue
  9. 4
      app/pages/@[publicSlug]/timeline/index.vue
  10. 2
      app/pages/index/index.vue
  11. 6
      app/pages/me/profile/index.vue
  12. 4
      app/pages/p/[publicSlug]/t/[shareToken].vue
  13. BIN
      packages/drizzle-pkg/db.sqlite
  14. 7
      server/api/public/profile/[publicSlug]/home-header.get.ts

6
app/components/AppShell.vue

@ -10,7 +10,7 @@ withDefaults(
)
const route = useRoute()
const { loggedIn, user, refresh, clear, pending } = useAuthSession()
const { loggedIn, user, refresh, clear, initialized } = useAuthSession()
const { fetchData } = useClientApi()
const { allowRegister, siteName } = useGlobalConfig()
@ -93,7 +93,7 @@ async function logout() {
try {
await fetchData<{ success: boolean }>('/api/auth/logout', { method: 'POST' })
clear()
await navigateTo('/login')
await navigateTo('/')
} finally {
logoutLoading.value = false
}
@ -158,7 +158,7 @@ async function logout() {
</div>
<div class="flex shrink-0 items-center gap-2">
<template v-if="pending && !loggedIn">
<template v-if="!initialized">
<USkeleton class="h-9 w-24 rounded-md" />
</template>

4
app/components/PostComments.vue

@ -164,10 +164,10 @@ async function submitComment() {
<h2 class="text-lg font-semibold">
评论
</h2>
<p v-if="pending" class="text-muted">
<p v-if="pending && !data" class="text-muted">
加载评论
</p>
<p v-else-if="error" class="text-muted">
<p v-else-if="error && !data" class="text-muted">
评论加载失败
</p>
<div v-else class="space-y-3">

25
app/layouts/public.vue

@ -7,7 +7,7 @@ import {
import { unwrapApiBody, type ApiResponse } from '../utils/http/factory'
const route = useRoute()
const { loggedIn, pending, refresh } = useAuthSession()
const { loggedIn, refresh, initialized } = useAuthSession()
const { siteName } = useGlobalConfig()
const showPublicLayoutToggle = computed(() => /^\/@[^/]+$/.test(route.path))
@ -40,14 +40,25 @@ const { data: publicHomeHeader } = await useAsyncData(
const headerBrandTo = computed(() => (profileSlug.value ? `/@${profileSlug.value}` : '/'))
const headerBrandTitle = computed(() => {
if (profileSlug.value && publicHomeHeader.value?.title) {
return publicHomeHeader.value.title
if (!profileSlug.value) {
return siteName.value
}
const t = publicHomeHeader.value?.title
if (typeof t === 'string' && t.trim().length) {
return t.trim()
}
return siteName.value
})
const headerBrandIconUrl = computed(() =>
profileSlug.value ? publicHomeHeader.value?.iconUrl ?? null : null,
)
const headerBrandIconUrl = computed(() => {
if (!profileSlug.value) {
return null
}
const u = publicHomeHeader.value?.iconUrl
if (typeof u !== 'string' || !u.trim()) {
return null
}
return u.trim()
})
type LayoutBySlug = Record<string, PublicHomeLayoutMode>
@ -137,7 +148,7 @@ onMounted(() => {
<span class="hidden sm:inline">阅读</span>
</UButton>
</div>
<template v-if="pending && !loggedIn">
<template v-if="!initialized">
<USkeleton class="h-5 w-12 rounded" />
</template>
<NuxtLink

4
app/pages/@[publicSlug]/about/index.vue

@ -37,10 +37,10 @@ useHead(() => ({
</script>
<template>
<div v-if="pending" class="text-muted py-10">
<div v-if="pending && !data" class="text-muted py-10">
<UContainer>加载中</UContainer>
</div>
<UContainer v-else-if="error" class="py-10">
<UContainer v-else-if="error && !data" class="py-10">
<UAlert color="error" title="无法加载页面" description="该用户没有公开的简介,或主页不存在。" />
</UContainer>
<UContainer v-else-if="data" class="py-10 max-w-3xl space-y-8">

4
app/pages/@[publicSlug]/index.vue

@ -148,10 +148,10 @@ const showBioReadMore = computed(() => {
</script>
<template>
<div v-if="pending" class="text-muted py-10">
<div v-if="pending && !data" class="text-muted py-10">
<UContainer>加载中</UContainer>
</div>
<UContainer v-else-if="error" class="py-10">
<UContainer v-else-if="error && !data" class="py-10">
<UAlert color="error" title="无法加载主页" />
</UContainer>

4
app/pages/@[publicSlug]/posts/[postSlug].vue

@ -80,10 +80,10 @@ const editPostHref = computed(() =>
<template>
<UContainer class="py-10 space-y-6">
<div v-if="pending" class="text-muted">
<div v-if="pending && !data" class="text-muted">
加载中
</div>
<UAlert v-else-if="error" color="error" title="文章不存在或未公开" />
<UAlert v-else-if="error && !data" color="error" title="文章不存在或未公开" />
<template v-else-if="data">
<div class="flex flex-wrap items-center gap-2">
<UButton :to="`/@${publicSlug}`" variant="ghost" color="neutral" size="sm" class="-ml-2">

4
app/pages/@[publicSlug]/posts/index.vue

@ -77,11 +77,11 @@ const { data, pending, error } = await useAsyncData(
<template>
<UContainer class="py-8 lg:py-10 max-w-6xl">
<div v-if="pending" class="text-muted py-10">
<div v-if="pending && !data" class="text-muted py-10">
加载中
</div>
<UAlert
v-else-if="error"
v-else-if="error && !data"
color="error"
title="无法加载文章列表"
class="my-6"

4
app/pages/@[publicSlug]/reading/index.vue

@ -89,11 +89,11 @@ const { data, pending, error } = await useAsyncData(
<template>
<UContainer class="py-8 lg:py-10 max-w-6xl">
<div v-if="pending" class="text-muted py-10">
<div v-if="pending && !data" class="text-muted py-10">
加载中
</div>
<UAlert
v-else-if="error"
v-else-if="error && !data"
color="error"
title="无法加载阅读列表"
class="my-6"

4
app/pages/@[publicSlug]/timeline/index.vue

@ -81,11 +81,11 @@ const { data, pending, error } = await useAsyncData(
<template>
<UContainer class="py-8 lg:py-10 max-w-6xl">
<div v-if="pending" class="text-muted py-10">
<div v-if="pending && !data" class="text-muted py-10">
加载中
</div>
<UAlert
v-else-if="error"
v-else-if="error && !data"
color="error"
title="无法加载时光机"
class="my-6"

2
app/pages/index/index.vue

@ -39,7 +39,7 @@ async function logout() {
try {
await fetchData<{ success: boolean }>('/api/auth/logout', { method: 'POST' })
clear()
await navigateTo('/login')
await navigateTo('/')
} finally {
logoutLoading.value = false
}

6
app/pages/me/profile/index.vue

@ -243,14 +243,14 @@ async function save() {
<UFormField
label="公开主页顶栏名称"
name="publicHomeHeaderTitle"
description="在 /@你的 slug 页面左上角显示。留空则使用昵称,昵称也为空时使用站点名称。"
description="在 /@你的 slug 页面左上角显示。留空则使用全站站点名称。"
>
<UInput v-model="state.publicHomeHeaderTitle" maxlength="64" placeholder="可选" />
<UInput v-model="state.publicHomeHeaderTitle" maxlength="64" placeholder="可选,默认与站点名称相同" />
</UFormField>
<UFormField
label="公开主页顶栏图标"
name="publicHomeHeaderIconUrl"
description="留空则使用「公开」可见的头像;若头像非公开则显示默认图标。支持站内路径或 http(s) 链接。"
description="留空则显示默认图标(与站点顶栏一致)。支持站内路径或 http(s) 链接。"
>
<div class="flex flex-col gap-3 sm:flex-row sm:items-start">
<span class="flex h-10 w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-primary/10 text-primary ring-1 ring-default">

4
app/pages/p/[publicSlug]/t/[shareToken].vue

@ -36,10 +36,10 @@ const renderedUnlistedPostBody = computed(() => {
<template>
<UContainer class="py-10 space-y-6">
<div v-if="pending" class="text-muted">
<div v-if="pending && !data" class="text-muted">
加载中
</div>
<UAlert v-else-if="error" color="error" title="链接无效或内容已不存在" />
<UAlert v-else-if="error && !data" color="error" title="链接无效或内容已不存在" />
<template v-else-if="data">
<UBadge color="neutral">
{{ data.kind }}

BIN
packages/drizzle-pkg/db.sqlite

Binary file not shown.

7
server/api/public/profile/[publicSlug]/home-header.get.ts

@ -27,11 +27,10 @@ export default defineEventHandler(async (event) => {
const configuredTitle = typeof titleCfg === "string" ? titleCfg.trim() : "";
const configuredIcon = typeof iconCfg === "string" ? iconCfg.trim() : "";
const publicAvatar = owner.avatarVisibility === "public" ? owner.avatar : null;
const nickname = owner.nickname?.trim() ?? "";
const site = typeof siteName === "string" ? siteName.trim() : "";
const title = configuredTitle || nickname || siteName;
const iconUrl = configuredIcon || publicAvatar || null;
const title = configuredTitle || site;
const iconUrl = configuredIcon.length > 0 ? configuredIcon : null;
return R.success({ title, iconUrl });
});

Loading…
Cancel
Save