From 0a720e6cd76b104462495589bed636c4a81c6ea5 Mon Sep 17 00:00:00 2001 From: Andrei Ivascu <7030530+aivascu@users.noreply.github.com> Date: Tue, 8 Sep 2026 11:27:48 +0300 Subject: [PATCH] Add article updated dates, sitemap lastmod, and Atom feed. --- .gitignore | 1 + site/app/composables/usePageSeo.ts | 47 +++-- site/app/pages/docs/[...slug].vue | 15 +- site/app/utils/formatDocsUpdatedDate.ts | 69 +++++++ site/content.config.ts | 5 + site/content/docs/5.integrations/10.tunit.md | 1 + site/nuxt.config.ts | 7 + site/public/llms.txt | 3 +- site/readme.md | 24 ++- site/scripts/prepare-agent-assets.mjs | 207 +++++++++++++++---- site/tests/formatDocsUpdatedDate.test.ts | 38 ++++ 11 files changed, 355 insertions(+), 62 deletions(-) create mode 100644 site/app/utils/formatDocsUpdatedDate.ts create mode 100644 site/tests/formatDocsUpdatedDate.test.ts diff --git a/.gitignore b/.gitignore index 7102b4e..ff4813e 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ site/public/api-meta/ site/public/api-catalog.json site/public/docs-markdown/ site/public/sitemap.xml +site/public/feed.xml ############### # OS / IDE diff --git a/site/app/composables/usePageSeo.ts b/site/app/composables/usePageSeo.ts index e1ed9bf..d818244 100644 --- a/site/app/composables/usePageSeo.ts +++ b/site/app/composables/usePageSeo.ts @@ -12,6 +12,8 @@ type PageSeoOptions = { title?: MaybeRefOrGetter description?: MaybeRefOrGetter image?: MaybeRefOrGetter + /** Article last-updated day as YYYY-MM-DD (adds Open Graph modified_time). */ + modifiedTime?: MaybeRefOrGetter } export function usePageSeo(options: PageSeoOptions = {}) { @@ -22,23 +24,38 @@ export function usePageSeo(options: PageSeoOptions = {}) { const description = computed(() => toValue(options.description) ?? DEFAULT_DESCRIPTION) const image = computed(() => `${siteUrl}${toValue(options.image) ?? DEFAULT_OG_IMAGE}`) const url = computed(() => `${siteUrl}${route.path}`) + const modifiedTime = computed(() => { + const day = toValue(options.modifiedTime) + return day ? `${day}T00:00:00.000Z` : undefined + }) useHead({ title, - meta: computed(() => [ - { name: 'description', content: description.value, tagPriority: seoTagPriority }, - { property: 'og:site_name', content: 'AutoFixture', tagPriority: seoTagPriority }, - { property: 'og:type', content: 'website', tagPriority: seoTagPriority }, - { property: 'og:title', content: title.value, tagPriority: seoTagPriority }, - { property: 'og:description', content: description.value, tagPriority: seoTagPriority }, - { property: 'og:image', content: image.value, tagPriority: seoTagPriority }, - { property: 'og:image:width', content: OG_IMAGE_WIDTH, tagPriority: seoTagPriority }, - { property: 'og:image:height', content: OG_IMAGE_HEIGHT, tagPriority: seoTagPriority }, - { property: 'og:url', content: url.value, tagPriority: seoTagPriority }, - { name: 'twitter:card', content: 'summary_large_image', tagPriority: seoTagPriority }, - { name: 'twitter:title', content: title.value, tagPriority: seoTagPriority }, - { name: 'twitter:description', content: description.value, tagPriority: seoTagPriority }, - { name: 'twitter:image', content: image.value, tagPriority: seoTagPriority }, - ]), + meta: computed(() => { + const tags = [ + { name: 'description', content: description.value, tagPriority: seoTagPriority }, + { property: 'og:site_name', content: 'AutoFixture', tagPriority: seoTagPriority }, + { property: 'og:type', content: 'website', tagPriority: seoTagPriority }, + { property: 'og:title', content: title.value, tagPriority: seoTagPriority }, + { property: 'og:description', content: description.value, tagPriority: seoTagPriority }, + { property: 'og:image', content: image.value, tagPriority: seoTagPriority }, + { property: 'og:image:width', content: OG_IMAGE_WIDTH, tagPriority: seoTagPriority }, + { property: 'og:image:height', content: OG_IMAGE_HEIGHT, tagPriority: seoTagPriority }, + { property: 'og:url', content: url.value, tagPriority: seoTagPriority }, + { name: 'twitter:card', content: 'summary_large_image', tagPriority: seoTagPriority }, + { name: 'twitter:title', content: title.value, tagPriority: seoTagPriority }, + { name: 'twitter:description', content: description.value, tagPriority: seoTagPriority }, + { name: 'twitter:image', content: image.value, tagPriority: seoTagPriority }, + ] + + if (modifiedTime.value) { + tags.push( + { property: 'article:modified_time', content: modifiedTime.value, tagPriority: seoTagPriority }, + { property: 'og:updated_time', content: modifiedTime.value, tagPriority: seoTagPriority }, + ) + } + + return tags + }), }) } diff --git a/site/app/pages/docs/[...slug].vue b/site/app/pages/docs/[...slug].vue index 51b34ea..5f74f7a 100644 --- a/site/app/pages/docs/[...slug].vue +++ b/site/app/pages/docs/[...slug].vue @@ -1,4 +1,6 @@