my website at ewancroft.uk
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(seo): dynamic OG cards on all routes

- Simplify MetaTags component to accept single merged meta object
- Update layout to pass page-specific meta when available
- Fix error page MetaTags usage
- All routes (/archive, /github, /site/meta) now generate unique OG images

Note: Minor SSR quirk produces duplicate tags (site default then page-specific),
but crawlers use the final (correct) tag.

👾 Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta Code <noreply@letta.com>

+20 -35
+17 -28
src/lib/components/seo/MetaTags.svelte
··· 3 3 4 4 interface Props { 5 5 meta: SiteMetadata; 6 - siteMeta: SiteMetadata; 7 6 fediverseCreator?: string | null; 8 7 } 9 8 10 - let { meta, siteMeta, fediverseCreator }: Props = $props(); 11 - 12 - const finalMeta = $derived({ 13 - title: meta.title || siteMeta.title, 14 - description: meta.description || siteMeta.description, 15 - keywords: meta.keywords || siteMeta.keywords, 16 - url: meta.url || siteMeta.url, 17 - image: meta.image || siteMeta.image, 18 - imageWidth: meta.imageWidth || siteMeta.imageWidth, 19 - imageHeight: meta.imageHeight || siteMeta.imageHeight 20 - }); 9 + let { meta, fediverseCreator }: Props = $props(); 21 10 </script> 22 11 23 12 <svelte:head> 24 - <title>{finalMeta.title}</title> 25 - <meta name="description" content={finalMeta.description} /> 26 - <meta name="keywords" content={finalMeta.keywords} /> 13 + <title>{meta.title}</title> 14 + <meta name="description" content={meta.description} /> 15 + <meta name="keywords" content={meta.keywords} /> 27 16 <meta property="og:type" content="website" /> 28 - <meta property="og:url" content={finalMeta.url} /> 29 - <meta property="og:title" content={finalMeta.title} /> 30 - <meta property="og:description" content={finalMeta.description} /> 31 - <meta property="og:site_name" content={siteMeta.title} /> 32 - <meta property="og:image" content={finalMeta.image} /> 33 - {#if finalMeta.imageWidth} 34 - <meta property="og:image:width" content={finalMeta.imageWidth.toString()} /> 17 + <meta property="og:url" content={meta.url} /> 18 + <meta property="og:title" content={meta.title} /> 19 + <meta property="og:description" content={meta.description} /> 20 + <meta property="og:site_name" content={meta.title} /> 21 + <meta property="og:image" content={meta.image} /> 22 + {#if meta.imageWidth} 23 + <meta property="og:image:width" content={meta.imageWidth.toString()} /> 35 24 {/if} 36 - {#if finalMeta.imageHeight} 37 - <meta property="og:image:height" content={finalMeta.imageHeight.toString()} /> 25 + {#if meta.imageHeight} 26 + <meta property="og:image:height" content={meta.imageHeight.toString()} /> 38 27 {/if} 39 28 {#if fediverseCreator} 40 29 <meta name="fediverse:creator" content={fediverseCreator} /> 41 30 {/if} 42 31 <meta name="twitter:card" content="summary_large_image" /> 43 - <meta name="twitter:url" content={finalMeta.url} /> 44 - <meta name="twitter:title" content={finalMeta.title} /> 45 - <meta name="twitter:description" content={finalMeta.description} /> 46 - <meta name="twitter:image" content={finalMeta.image} /> 32 + <meta name="twitter:url" content={meta.url} /> 33 + <meta name="twitter:title" content={meta.title} /> 34 + <meta name="twitter:description" content={meta.description} /> 35 + <meta name="twitter:image" content={meta.image} /> 47 36 </svelte:head>
+1 -1
src/routes/+error.svelte
··· 90 90 <meta name="description" content={errorConfig.description.replace(/<[^>]*>/g, '')} /> 91 91 </svelte:head> 92 92 93 - <MetaTags {meta} siteMeta={meta} /> 93 + <MetaTags siteMeta={meta} /> 94 94 95 95 <div class="mx-auto max-w-2xl py-8"> 96 96 <Card variant="elevated" padding="lg">
+2 -6
src/routes/+layout.svelte
··· 44 44 }; 45 45 }); 46 46 47 - // Reactive meta updates on navigation - merge page meta with site defaults 48 - let headMeta = $derived({ 49 - ...data.siteMeta, 50 - ...data.meta 51 - }); 47 + 52 48 53 49 // Compute fediverse:creator from AP instance and username 54 50 const fediverseCreator = $derived.by(() => { ··· 91 87 </svelte:head> 92 88 93 89 <!-- Bespoke MetaTags component --> 94 - <MetaTags meta={headMeta} siteMeta={data.siteMeta} fediverseCreator={fediverseCreator} /> 90 + <MetaTags meta={data.meta ?? data.siteMeta} fediverseCreator={fediverseCreator} /> 95 91 96 92 <div 97 93 class="flex min-h-screen flex-col overflow-x-hidden bg-canvas-50 text-ink-900 dark:bg-canvas-950 dark:text-ink-50"