my website at ewancroft.uk
6
fork

Configure Feed

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

feat(metadata): Revert to bespoke metadata per page

+53 -22
+48
src/lib/components/seo/MetaTags.svelte
··· 1 + <script lang="ts"> 2 + import type { SiteMetadata } from '$lib/helper/siteMeta'; 3 + 4 + interface Props { 5 + meta: SiteMetadata; 6 + siteMeta: SiteMetadata; 7 + } 8 + 9 + let { meta, siteMeta }: Props = $props(); 10 + 11 + // Merge with defaults 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 + }); 21 + </script> 22 + 23 + <svelte:head> 24 + <title>{finalMeta.title}</title> 25 + <meta name="description" content={finalMeta.description} /> 26 + <meta name="keywords" content={finalMeta.keywords} /> 27 + 28 + <!-- Open Graph / Facebook --> 29 + <meta property="og:type" content="website" /> 30 + <meta property="og:url" content={finalMeta.url} /> 31 + <meta property="og:title" content={finalMeta.title} /> 32 + <meta property="og:description" content={finalMeta.description} /> 33 + <meta property="og:site_name" content={siteMeta.title} /> 34 + <meta property="og:image" content={finalMeta.image} /> 35 + {#if finalMeta.imageWidth} 36 + <meta property="og:image:width" content={finalMeta.imageWidth.toString()} /> 37 + {/if} 38 + {#if finalMeta.imageHeight} 39 + <meta property="og:image:height" content={finalMeta.imageHeight.toString()} /> 40 + {/if} 41 + 42 + <!-- Twitter --> 43 + <meta name="twitter:card" content="summary_large_image" /> 44 + <meta name="twitter:url" content={finalMeta.url} /> 45 + <meta name="twitter:title" content={finalMeta.title} /> 46 + <meta name="twitter:description" content={finalMeta.description} /> 47 + <meta name="twitter:image" content={finalMeta.image} /> 48 + </svelte:head>
+1
src/lib/components/seo/index.ts
··· 1 + export { default as MetaTags } from './MetaTags.svelte';
+4 -22
src/routes/+layout.svelte
··· 1 1 <script lang="ts"> 2 2 import '../app.css'; 3 3 import { Header, Footer, ScrollToTop } from '$lib/components/layout'; 4 + import { MetaTags } from '$lib/components/seo'; 4 5 import { createSiteMeta, type SiteMetadata } from '$lib/helper/siteMeta'; 5 - import { generateMetaTags } from '$lib/helper/metaTags'; 6 - import { afterNavigate } from '$app/navigation'; 7 6 import type { Snippet } from 'svelte'; 8 7 9 8 interface Props { ··· 22 21 ...data.siteMeta, 23 22 ...data.meta 24 23 })); 25 - 26 - // Generate meta tags for SEO / OG / Twitter 27 - let metaTags = $derived(generateMetaTags(headMeta, data.siteMeta)); 28 - 29 - // Update document title and meta tags after navigation 30 - afterNavigate(() => { 31 - // Force update of document title 32 - if (typeof document !== 'undefined') { 33 - document.title = headMeta.title; 34 - } 35 - }); 36 24 </script> 37 25 38 26 <svelte:head> ··· 58 46 <link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png" /> 59 47 <link rel="icon" href="/favicon/favicon.ico" sizes="any" /> 60 48 <link rel="manifest" href="/favicon/site.webmanifest" /> 61 - <title>{headMeta.title}</title> 62 - 63 - {#each metaTags as tag} 64 - {#if tag.name} 65 - <meta name={tag.name} content={tag.content} /> 66 - {:else if tag.property} 67 - <meta property={tag.property} content={tag.content} /> 68 - {/if} 69 - {/each} 70 49 </svelte:head> 50 + 51 + <!-- Bespoke MetaTags component --> 52 + <MetaTags meta={headMeta} siteMeta={data.siteMeta} /> 71 53 72 54 <div class="flex min-h-screen flex-col bg-canvas-50 text-ink-900 dark:bg-canvas-950 dark:text-ink-50"> 73 55 <Header />