Files
vue-journal-layer/app/journal-pages/PostIndexPage.vue
Jakub Zych 642c25a0d0 feat: ItemList nodes on listing pages
The index, category, tag and author pages add an ItemList node
(@id <page URL>#itemlist, a ListItem with the absolute URL of each post
shown, positions continuing across pages) through vue-seo-layer's
useSchemaNode, so the page keeps one JSON-LD script with one @graph
(useJournalItemList, journalItemList).
2026-11-04 13:55:55 +01:00

47 lines
1.9 KiB
Vue

<script setup lang="ts">
// journal-index: the post list, paginated with ?page=N (or the path form).
// A non-numeric page or a page past the last one is a real 404.
import { pageFromRoute, pageOutOfRange } from '../utils/pagination.ts'
import { listTitle } from '../utils/seo.ts'
import { journalBreadcrumbsOn, toListPost } from '../utils/view.ts'
import type { JournalModuleOptions } from '../utils/types.ts'
// Re-run setup (and its 404 checks) on every query change.
definePageMeta({ key: (route) => route.fullPath })
const route = useRoute()
const api = useJournalApi()
const cfg = useRuntimeConfig().public.journal as JournalModuleOptions
const { t } = useI18n()
const page = pageFromRoute(route)
if (page === null) throw createError({ statusCode: 404, statusMessage: 'Page not found', fatal: true })
const { data, error } = await useAsyncData(
`journal-index-${page}`,
() => api.listPosts({ page, perPage: cfg.perPage.index, sort: cfg.sort }),
{ transform: (res) => ({ ...res, data: res.data.map(toListPost) }) },
)
if (error.value || !data.value) {
throw createError({ statusCode: (error.value as { statusCode?: number } | undefined)?.statusCode ?? 500, fatal: true })
}
if (pageOutOfRange(page, data.value.meta.last_page)) {
throw createError({ statusCode: 404, statusMessage: 'Page not found', fatal: true })
}
const title = listTitle(t('journal.index.title'), page, t('journal.pagination.pageTitle', { page }))
useSeoMeta({ title, ogTitle: title })
const crumbs = journalBreadcrumbsOn(cfg.breadcrumbs)
useJournalItemList(() => data.value?.data, () => data.value?.meta)
</script>
<template>
<section v-if="data" class="journal-index">
<SeoBreadcrumbs v-if="crumbs" />
<JournalIndexHeader :page="page" />
<JournalPostList :posts="data.data" />
<JournalPagination :current="data.meta.current_page" :last="data.meta.last_page" />
<JournalRssLink />
</section>
</template>