Reactive SEO - Global default in root layout, reactive reusable component, data props

This commit is contained in:
Matthieu Morin 2024-04-03 16:36:27 +02:00
parent 8291443c80
commit 0e30d0a539
4 changed files with 184 additions and 100 deletions

View File

@ -0,0 +1,150 @@
<!-- <script lang="ts">
import * as conf from '$lib/config'
import { getImageLink } from '$lib/images';
import type { ExtendedService, ExtendedCategory } from '$lib/types/service';
export let data: ExtendedService | ExtendedCategory
let seoData: ExtendedService | ExtendedCategory
export let title: string;
export let description: string;
export let type: string;
export let keywords: string;
export let image: string;
export let canonical: string;
export let twitter: {
title?: string;
description?: string;
image?: string;
} = {};
</script>
<svelte:head>
<title>{data.title}</title>
<meta name="robots" content="index, follow" />
<meta name="googlebot" content="index,follow" />
{#if data.description}
<meta name="description" content={data.description} />
{/if}
<meta name="keywords" content={keywords} />
{#if data.canonical}
<link rel="canonical" href={data.canonical} />
{/if}
<meta property="og:site_name" content="{conf.title}" />
<meta property="og:title" content={data.title} />
<meta property="og:type" content={data.type ? data.type : 'site'} />
{#if data.description}
<meta property="og:description" content={data.description} />
{/if}
{#if data.canonical}
<meta property="og:url" content={data.canonical} />
{/if}
<meta property="og:image" content={getImageLink({id: data.id, h:, w:})} />
<meta property="fb:admins" content="${conf.FBNumID}" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={data.title} />
{#if data.description}
<meta name="twitter:description" content={data.description} />
{/if}
<meta name="twitter:image" content={twitter.image || image} />
<meta property="article:published_time" content={data.frontmatter?.date} />
{#each data.frontmatter?.tags as tag (tag)}
<meta property="article:tag" content={tag} />
{/each}
</svelte:head> -->
<!-- src/lib/components/SEO.svelte -->
<script lang="ts">
import { page } from '$app/stores';
import * as conf from '$lib/config';
export let seoData: {
title: string;
description: string;
type: string;
keywords: string;
image: string;
canonical?: string;
twitter?: {
title?: string;
description?: string;
image?: string;
};
frontmatter?: {
date: string;
tags: string[];
};
};
$: title = seoData.title;
$: description = seoData.description;
$: type = seoData.type;
$: keywords = seoData.keywords;
$: image = seoData.image;
$: canonical = seoData.canonical;
$: twitter = seoData.twitter;
$: frontmatter = seoData.frontmatter;
</script>
<svelte:head>
<title>{title}</title>
<meta name="robots" content="index, follow" />
<meta name="googlebot" content="index,follow" />
{#if description}
<meta name="description" content={description} />
{/if}
<meta name="keywords" content={keywords} />
{#if canonical}
<link rel="canonical" href={canonical} />
{/if}
<meta property="og:site_name" content={conf.title} />
<meta property="og:title" content={title} />
{#if description}
<meta property="og:description" content={description} />
{/if}
{#if canonical}
<meta property="og:url" content={canonical} />
{/if}
<meta property="og:image" content={image} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={twitter?.title || title} />
{#if twitter?.description || description}
<meta name="twitter:description" content={twitter?.description || description} />
{/if}
<meta name="twitter:image" content={twitter?.image || image} />
<!--If there is frontmatter, make it into an article-->
{#if frontmatter?}
<meta property="og:type" content="article" />
{:else}
<meta property="og:type" content={type || 'website'} />
{/if}
{#if frontmatter?.date}
<meta property="article:published_time" content={frontmatter.date} />
{/if}
{#if frontmatter?.tags}
{#each frontmatter.tags as tag}
<meta property="article:tag" content={tag} />
{/each}
{/if}
</svelte:head>

View File

@ -1,20 +0,0 @@
<script lang="ts">
import * as conf from '$lib/config'
import type { ExtendedServiceItem } from '$lib/types/service';
export let openGraphData: ExtendedServiceItem;
</script>
<svelte:head>
<title>{openGraphData.title}</title>
<meta name="description" content={openGraphData.description} />
<meta property="og:title" content={openGraphData.title} />
<meta property="og:type" content="article" />
<meta property="og:description" content={openGraphData.description} />
<meta property="og:url" content="{conf.url}{openGraphData.id}" />
<meta property="og:image" content={openGraphData.image} />
<meta property="article:published_time" content={openGraphData.date} />
{#each tags as tag (tag)} <!-- FIX THIS tags is not defined, but it needs to be "eached somehow"-->
<meta property="article:tag" content={openGraphData.tag} />
{/each}
</svelte:head>

View File

@ -1,56 +0,0 @@
<script lang="ts">
import * as conf from '$lib/config'
import type { ExtendedService, ExtendedCategory } from '$lib/types/service';
export let data: ExtendedService | ExtendedCategory
export let title: string;
export let description: string;
export let type: string;
export let keywords: string;
export let image: string;
export let canonical: string = undefined;
export let twitter: {
title?: string;
description?: string;
image?: string;
} = {};
conf.</script>
<svelte:head>
<title>{data.title}</title>
<meta name="robots" content="index, follow" />
<meta name="googlebot" content="index,follow" />
{#if data.description}
<meta name="description" content={data.description} />
{/if}
<meta name="keywords" content={keywords} />
{#if data.canonical}
<link rel="canonical" href={data.canonical} />
{/if}
<meta property="og:site_name" content="{conf.title}" />
<meta property="og:title" content={data.title} />
<meta property="og:type" content={data.type ? data.type : 'site'} />
{#if data.description}
<meta property="og:description" content={data.description} />
{/if}
{#if data.canonical}
<meta property="og:url" content={data.canonical} />
{/if}
<meta property="og:image" content={data.image} />
<meta property="fb:admins" content="{conf.FBNumID}" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={data.title} />
{#if data.description}
<meta name="twitter:description" content={data.description} />
{/if}
<meta name="twitter:image" content={twitter.image || image} />
<meta property="article:published_time" content={data.frontmatter?.date} />
{#each data.frontmatter?.tags as tag (tag)}
<meta property="article:tag" content={tag} />
{/each}
</svelte:head>

View File

@ -27,24 +27,34 @@
import MainFooter from '$lib/components/MainFooter.svelte';
// SEO Meta tags
const metaDefaults = {
title: 'BeautySalon',
description: 'BeautySalon Popis.',
image: 'https://user-images.githubusercontent.com/1509726/212382766-f29b9c9a-82e3-44c2-b911-b17a9197e5b9.jpg'
};
const meta = {
title: metaDefaults.title,
description: metaDefaults.description,
image: metaDefaults.image,
// Article
article: { publishTime: '', modifiedTime: '', author: '' },
// Twitter
twitter: {
title: metaDefaults.title,
description: metaDefaults.description,
image: metaDefaults.image
}
};
import SEO from '$lib/components/SEO.svelte'
$: seoData = $page.data.seoData || {
title: 'KKosmetickySalon - Klára Morinová',
description: 'Přijeďte si ke mně pro odbornou péči o Vaši pleť. Jsem certifikovaná kosmetička a makeup artistka, provádím Permanentní Make-up, vizážistiku, ošetřovací a zeštihlovací procedury, a mnoho dalšího... Vše s ohledem na vaše zdraví. Zarezervujte si péči o svůj vzhled přes moje stránky nyní!',
keywords: 'kosmetika, vizáž, pleť, Písek, kosmetička, permanentní makeup, ',
image: '/logo-text.png',
type: 'website',
};
// const metaDefaults = {
// title: 'BeautySalon',
// description: 'BeautySalon Popis.',
// image: 'https://user-images.githubusercontent.com/1509726/212382766-f29b9c9a-82e3-44c2-b911-b17a9197e5b9.jpg'
// };
// const meta = {
// title: metaDefaults.title,
// description: metaDefaults.description,
// image: metaDefaults.image,
// // Article
// article: { publishTime: '', modifiedTime: '', author: '' },
// // Twitter
// twitter: {
// title: metaDefaults.title,
// description: metaDefaults.description,
// image: metaDefaults.image
// }
// };
// Scroll to anchor
@ -63,15 +73,15 @@
</script>
<!-- SEO -->
<svelte:head>
<!-- <svelte:head>
<title>{meta.title}</title>
<!-- Meta Tags -->
Meta Tags
<meta name="title" content={meta.title} />
<meta name="description" content={meta.description} />
<meta name="keywords" content="krása, kosmetika, permanentní makeup, revitalizace pleti, oprava pleti, salón, kosmetička, kosmetický salón, Písek, obočí, vytrhání, natočení řas, řasy" />
<meta name="theme-color" content="#242c46" />
<meta name="author" content="Klára Morinová" />
<!-- Open Graph - https://ogp.me/ -->
Open Graph - https://ogp.me/
<meta property="og:site_name" content="BeautySalon" />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://www.beautysalon.cz{$page.url.pathname}" />
@ -84,12 +94,12 @@
<meta property="og:image:width" content="1707" />
<meta property="og:image:height" content="1233" />
<!-- Open Graph: Twitter -->
Open Graph: Twitter
<meta name="twitter:title" content={meta.twitter.title} />
<meta name="twitter:description" content={meta.twitter.description} />
<meta name="twitter:image" content={meta.twitter.image} />
</svelte:head>
</svelte:head> -->
<SEO {seoData}/>
<!-- <Analytics /> -->
<!-- App Shell -->
<Drawer />