Browse Source

feat(posts): remove newer/older nav; edit link on public post for owner; expose post id in public API

Made-with: Cursor
main
npmrun 16 hours ago
parent
commit
436d0e7693
  1. 31
      app/pages/@[publicSlug]/posts/[postSlug].vue
  2. 93
      app/pages/me/posts/[id].vue
  3. 1
      server/service/posts/index.ts

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

@ -2,6 +2,7 @@
import { unwrapApiBody, type ApiResponse } from '../../../utils/http/factory'
import { renderSafeMarkdown } from '../../../utils/render-markdown'
import { formatOccurredOnDisplay, occurredOnToIsoAttr } from '../../../utils/timeline-datetime'
import { useAuthSession } from '../../../composables/useAuthSession'
definePageMeta({
layout: 'public',
@ -10,8 +11,10 @@ definePageMeta({
const route = useRoute()
const publicSlug = computed(() => route.params.publicSlug as string)
const postSlug = computed(() => route.params.postSlug as string)
const { user, loggedIn, refresh: refreshAuth } = useAuthSession()
type Post = {
id: number
title: string
slug: string
excerpt: string
@ -45,6 +48,23 @@ watchEffect(() => {
useHead({ title: data.value.title })
}
})
onMounted(() => {
void refreshAuth(true)
})
/** 当前登录用户是否为该公开主页所有者(可编辑此文) */
const canEditPost = computed(() => {
const slug = user.value?.publicSlug
if (!loggedIn.value || !slug) {
return false
}
return slug === publicSlug.value
})
const editPostHref = computed(() =>
data.value && canEditPost.value ? `/me/posts/${data.value.id}` : '',
)
</script>
<template>
@ -54,9 +74,20 @@ watchEffect(() => {
</div>
<UAlert v-else-if="error" 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">
返回主页
</UButton>
<UButton
v-if="editPostHref"
:to="editPostHref"
color="neutral"
variant="soft"
size="sm"
>
编辑
</UButton>
</div>
<div v-if="data.coverUrl" class="flex justify-center">
<img
:src="data.coverUrl"

93
app/pages/me/posts/[id].vue

@ -4,8 +4,6 @@ import { useAuthSession } from '../../../composables/useAuthSession'
definePageMeta({ title: '编辑文章' })
type PostRow = { id: number; title: string; slug: string; visibility: string }
const route = useRoute()
const id = computed(() => route.params.id as string)
const { user, refresh: refreshAuth } = useAuthSession()
@ -20,27 +18,6 @@ const state = reactive({
})
const loading = ref(true)
const saving = ref(false)
const postsNav = ref<PostRow[]>([])
const currentNumericId = computed(() => Number.parseInt(id.value, 10))
const newerPost = computed((): PostRow | null => {
const list = postsNav.value
const idx = list.findIndex((p) => p.id === currentNumericId.value)
if (idx <= 0) {
return null
}
return list[idx - 1] ?? null
})
const olderPost = computed((): PostRow | null => {
const list = postsNav.value
const idx = list.findIndex((p) => p.id === currentNumericId.value)
if (idx < 0 || idx >= list.length - 1) {
return null
}
return list[idx + 1] ?? null
})
const publicPostHref = computed(() => {
const ps = user.value?.publicSlug
@ -50,18 +27,6 @@ const publicPostHref = computed(() => {
return `/@${ps}/posts/${encodeURIComponent(state.slug)}`
})
/** 公开文跳站点详情,否则进编辑页 */
function navTargetHref(p: PostRow | null) {
if (!p) {
return ''
}
const ps = user.value?.publicSlug
if (p.visibility === 'public' && ps) {
return `/@${ps}/posts/${encodeURIComponent(p.slug)}`
}
return `/me/posts/${p.id}`
}
async function load() {
loading.value = true
try {
@ -80,18 +45,8 @@ async function load() {
}
}
async function loadPostNav() {
try {
const res = await request<ApiResponse<{ posts: PostRow[] }>>('/api/me/posts')
postsNav.value = unwrapApiBody(res).posts
} catch {
postsNav.value = []
}
}
onMounted(() => {
void refreshAuth(true)
void loadPostNav()
void load()
})
@ -157,54 +112,6 @@ const shareUrl = computed(() => {
</div>
</div>
<UCard v-if="!loading" :ui="{ body: 'p-3 sm:p-4' }">
<div class="flex flex-wrap items-center gap-2">
<UButton
v-if="newerPost"
:to="navTargetHref(newerPost)"
variant="soft"
color="neutral"
size="sm"
leading-icon="i-lucide-chevron-up"
>
较新
</UButton>
<UButton
v-else
disabled
variant="soft"
color="neutral"
size="sm"
leading-icon="i-lucide-chevron-up"
>
较新
</UButton>
<UButton
v-if="olderPost"
:to="navTargetHref(olderPost)"
variant="soft"
color="neutral"
size="sm"
leading-icon="i-lucide-chevron-down"
>
较旧
</UButton>
<UButton
v-else
disabled
variant="soft"
color="neutral"
size="sm"
leading-icon="i-lucide-chevron-down"
>
较旧
</UButton>
</div>
<p v-if="newerPost || olderPost" class="text-xs text-muted mt-2">
顺序与列表一致最新在上公开文章打开站点详情其余进入对应编辑页
</p>
</UCard>
<div v-if="loading" class="text-muted">
加载中
</div>

1
server/service/posts/index.ts

@ -145,6 +145,7 @@ export async function getPublicPostByPublicSlugAndSlug(publicSlug: string, postS
}
const [row] = await dbGlobal
.select({
id: posts.id,
title: posts.title,
slug: posts.slug,
excerpt: posts.excerpt,

Loading…
Cancel
Save