From 30415f9f948a6fe008e2e56e034fd7026d476d71 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 23 Mar 2026 22:01:50 +0000 Subject: [PATCH 1/3] refactor: address additional review findings for Nuxt best practices - Remove unused @vueuse/nuxt module and dependency - Update compatibilityDate to 2025-03-01 for Nuxt 4 - Re-enable @typescript-eslint/no-explicit-any (no violations found) - Extract usePageSeo composable to deduplicate SEO meta across pages - Extract shared ContentButton type to replace duplicated inline types - Optimize [slug] pages to query by stem instead of fetching all entries - Add defineOgImage() to all pages for proper OG image generation - Document dangerous-clean-slate rationale in deploy workflow https://claude.ai/code/session_01D9Js2socgpErtmsWh88fMj --- .github/workflows/deploy.yml | 2 ++ app/components/landing/LabsTeaser.vue | 9 +-------- app/components/landing/SpeakingTeaser.vue | 9 +-------- app/composables/usePageSeo.ts | 20 ++++++++++++++++++++ app/pages/index.vue | 9 +++------ app/pages/labs/[slug].vue | 17 ++++++----------- app/pages/labs/index.vue | 9 +++------ app/pages/speaking/[slug].vue | 13 ++++++------- app/pages/speaking/index.vue | 9 +++------ app/utils/types.ts | 8 ++++++++ eslint.config.mjs | 6 +----- nuxt.config.ts | 3 +-- package.json | 1 - pnpm-lock.yaml | 20 -------------------- 14 files changed, 55 insertions(+), 80 deletions(-) create mode 100644 app/composables/usePageSeo.ts create mode 100644 app/utils/types.ts diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 7688b5b..65e5693 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -32,6 +32,8 @@ jobs: run: pnpm generate - name: Deploy via FTP + # Full sync: deletes remote files not present in local build to ensure + # a clean deployment matching the generated output exactly. uses: SamKirkland/FTP-Deploy-Action@v4.3.6 with: server: ${{ secrets.HOST }} diff --git a/app/components/landing/LabsTeaser.vue b/app/components/landing/LabsTeaser.vue index b83efca..a2dcc4c 100644 --- a/app/components/landing/LabsTeaser.vue +++ b/app/components/landing/LabsTeaser.vue @@ -2,14 +2,7 @@ type LabsSection = { title: string description: string - link: { - label: string - icon?: string - to?: string - color?: 'primary' | 'neutral' | 'success' | 'warning' | 'error' | 'info' - variant?: 'solid' | 'outline' | 'subtle' | 'soft' | 'ghost' | 'link' - target?: '_blank' | '_self' - } + link: ContentButton } defineProps<{ diff --git a/app/components/landing/SpeakingTeaser.vue b/app/components/landing/SpeakingTeaser.vue index bdc458a..2c2791b 100644 --- a/app/components/landing/SpeakingTeaser.vue +++ b/app/components/landing/SpeakingTeaser.vue @@ -3,14 +3,7 @@ type SpeakingSection = { title: string description: string note?: string - link: { - label: string - icon?: string - to?: string - color?: 'primary' | 'neutral' | 'success' | 'warning' | 'error' | 'info' - variant?: 'solid' | 'outline' | 'subtle' | 'soft' | 'ghost' | 'link' - target?: '_blank' | '_self' - } + link: ContentButton } defineProps<{ diff --git a/app/composables/usePageSeo.ts b/app/composables/usePageSeo.ts new file mode 100644 index 0000000..8370ccb --- /dev/null +++ b/app/composables/usePageSeo.ts @@ -0,0 +1,20 @@ +type SeoInput = { + title?: string + description?: string + seo?: { + title?: string + description?: string + } | null +} + +export function usePageSeo(page: SeoInput) { + const title = page.seo?.title || page.title + const description = page.seo?.description || page.description + + useSeoMeta({ + title, + ogTitle: title, + description, + ogDescription: description + }) +} diff --git a/app/pages/index.vue b/app/pages/index.vue index 093770d..266f61c 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -23,12 +23,9 @@ if (!page.value) { }) } -useSeoMeta({ - title: page.value?.seo.title || page.value?.title, - ogTitle: page.value?.seo.title || page.value?.title, - description: page.value?.seo.description || page.value?.description, - ogDescription: page.value?.seo.description || page.value?.description -}) +usePageSeo(page.value) + +defineOgImage()