Added SEO and structured data

This commit is contained in:
Aron August Hohmann 2026-06-14 18:42:27 +02:00
parent fdc26c9b92
commit c6d0fa30bb
8 changed files with 253 additions and 24 deletions

View file

@ -51,5 +51,14 @@
"contact_cta_body": "Interesse an einer Zusammenarbeit?",
"contact_cta_link": "Nachricht senden",
"contact_heading": "Kontakt",
"contact_intro": "Interesse an einer Zusammenarbeit oder Feedback zum Blog? Schreib mir gerne über einen meiner Socials oder per E-Mail."
"contact_intro": "Interesse an einer Zusammenarbeit oder Feedback zum Blog? Schreib mir gerne über einen meiner Socials oder per E-Mail.",
"meta_home_title": "Business Analyst & Solution Designer",
"meta_home_description": "Aron August Hohmann Business Analyst & Solution Designer in Wien. Anforderungsanalyse, Solution Design und Systemintegration für digitale Plattformen.",
"meta_blog_title": "Blog",
"meta_blog_description": "Artikel über Solution Design, Plattformentscheidungen und digitale Prozesse von Aron August Hohmann.",
"meta_contact_title": "Kontakt",
"meta_contact_description": "Kontakt aufnehmen mit Aron August Hohmann Business Analyst & Solution Designer in Wien."
}

View file

@ -52,5 +52,14 @@
"contact_cta_link": "Send a message",
"contact_heading": "Contact",
"contact_intro": "Interested in working together or have feedback about the blog? Reach out via one of my socials or drop me an email.",
"contact_email_label": "Email"
"contact_email_label": "Email",
"meta_home_title": "Business Analyst & Solution Designer",
"meta_home_description": "Aron August Hohmann Business Analyst & Solution Designer based in Vienna. Requirements analysis, solution design, and system integration for digital platforms.",
"meta_blog_title": "Blog",
"meta_blog_description": "Articles on solution design, platform decisions, and digital processes by Aron August Hohmann.",
"meta_contact_title": "Contact",
"meta_contact_description": "Get in touch with Aron August Hohmann Business Analyst & Solution Designer based in Vienna."
}

View file

@ -0,0 +1,57 @@
<script lang="ts">
interface ArticleMeta {
publishedTime: string;
tags?: string[];
}
interface Props {
title: string;
description: string;
type?: 'website' | 'article';
canonicalUrl: string;
article?: ArticleMeta;
jsonLd?: Record<string, unknown>;
}
let {
title,
description,
type = 'website',
canonicalUrl,
article,
jsonLd
}: Props = $props();
const fullTitle = `${title} | Aron August Hohmann`;
</script>
<svelte:head>
<title>{fullTitle}</title>
<meta name="description" content={description} />
<!-- Canonical -->
<link rel="canonical" href={canonicalUrl} />
<!-- Open Graph -->
<meta property="og:type" content={type} />
<meta property="og:title" content={fullTitle} />
<meta property="og:description" content={description} />
<meta property="og:url" content={canonicalUrl} />
<meta property="og:site_name" content="Aron August Hohmann" />
<meta property="og:image" content="https://aronhohmann.eu/images/aron_august_hohmann.avif" />
<!-- Article-specific OG -->
{#if type === 'article' && article}
<meta property="article:published_time" content={article.publishedTime} />
{#if article.tags}
{#each article.tags as tag (tag)}
<meta property="article:tag" content={tag} />
{/each}
{/if}
{/if}
<!-- JSON-LD -->
{#if jsonLd}
{@html `<script type="application/ld+json">${JSON.stringify(jsonLd)}<\/script>`}
{/if}
</svelte:head>

View file

@ -4,16 +4,29 @@
import { getLocale, locales, localizeHref } from '$lib/paraglide/runtime';
import { m } from '$lib/paraglide/messages.js';
import { page } from '$app/state';
let { children } = $props();
const localeNames: Record<string, string> = {
en: 'English',
de: 'Deutsch'
};
</script>
<svelte:head><link rel="icon" href={favicon} /></svelte:head>
<svelte:head>
<link rel="icon" href={favicon} />
<!-- hreflang alternates -->
{#each [...locales] as locale (locale)}
<link
rel="alternate"
hreflang={locale}
href={`https://aronhohmann.eu${page.data.translationSlug
? localizeHref(`/blog/${page.data.translationSlug}`, { locale })
: page.data.metadata
? localizeHref('/blog', { locale })
: localizeHref(page.url.pathname, { locale })}`}
/>
{/each}
<link rel="alternate" hreflang="x-default" href={`https://aronhohmann.eu${page.url.pathname}`} />
</svelte:head>
<!-- Header -->
<header class="border-b fixed border-black w-full z-50">
@ -21,19 +34,18 @@
<nav class="flex gap-5 text-white items-center justify-center min-h-10" style="background-color: #0a3d57;">
{#each [...locales].sort() as locale}
<a
href={page.data.translationSlug
? localizeHref(`/blog/${page.data.translationSlug}`, { locale })
: page.data.metadata
href={page.data.translationSlug
? localizeHref(`/blog/${page.data.translationSlug}`, { locale })
: page.data.metadata
? localizeHref('/blog', { locale })
: localizeHref(page.url.pathname, { locale })}
data-sveltekit-reload
class="transition cursor-pointer"
data-sveltekit-reload
class="transition cursor-pointer"
>
{getLocale() === locale ? `> ${localeNames[locale]} <` : localeNames[locale]}
{getLocale() === locale ? `> ${localeNames[locale]} <` : localeNames[locale]}
</a>
{/each}
</nav>
<!-- Main Navigation -->
<nav id="main" class="bg-white border-b border-gray-200 flex justify-center items-center gap-8 px-5 min-h-10">
<a href="/{getLocale()}">{ m.nav_about() }</a>
@ -51,14 +63,13 @@
<footer class="flex flex-col justify-center items-center gap-5 mt-30 text-white px-1.5 pt-12" style="background-color: #0a3d57;">
<div class="mb-15">
<img
src="/images/wappen_siegel.svg"
alt=""
width="200"
height="200"
style="filter: invert(1);"
src="/images/wappen_siegel.svg"
alt=""
width="200"
height="200"
style="filter: invert(1);"
/>
</div>
<div class="flex flex-row gap-2 mb-15">
<a href="/{getLocale()}">{ m.nav_about() }</a>
<span> | </span>
@ -68,13 +79,10 @@
<span> | </span>
<a href="/{getLocale()}/links">Links</a>
</div>
<div class="text-center">
<small>© Aron August Hohmann</small>
</div>
<div class="h-0.5"></div>
<nav class="text-xs text-center text-gray-200 w-full flex justify-center items-center gap-2 md:gap-5 min-h-10" style="background-color: #072d40;">
<a href="/{getLocale()}/l/imp">{ m.footer_imprint() }</a>
<span> | </span>

View file

@ -1,7 +1,44 @@
<script lang="ts">
import { m } from '$lib/paraglide/messages.js';
import { getLocale } from '$lib/paraglide/runtime';
import SEO from '$lib/components/SEO.svelte';
import { page } from '$app/state';
const locale = getLocale();
const canonicalUrl = `https://aronhohmann.eu${page.url.pathname}`;
const personJsonLd = {
'@context': 'https://schema.org',
'@type': 'Person',
name: 'Aron August Hohmann',
url: 'https://aronhohmann.eu',
image: 'https://aronhohmann.eu/images/aron_august_hohmann.avif',
jobTitle: 'Business Analyst & Solution Designer',
worksFor: {
'@type': 'Organization',
name: 'Holzkern Time for Nature GmbH'
},
address: {
'@type': 'PostalAddress',
addressLocality: 'Vienna',
addressCountry: 'AT'
},
sameAs: [
'https://www.linkedin.com/in/aron-august-hohmann/',
'https://aronhohmann.eu'
]
};
</script>
<SEO
title={m.meta_home_title()}
description={m.meta_home_description()}
type="website"
{canonicalUrl}
jsonLd={personJsonLd}
/>
<!-- Hero -->
<section class="flex flex-col md:flex-row items-center md:items-start gap-10 max-w-3xl mx-auto px-4 py-16">
<img

View file

@ -1,10 +1,45 @@
<script lang="ts">
import { m } from '$lib/paraglide/messages.js';
import {getLocale} from "$lib/paraglide/runtime";
import SEO from '$lib/components/SEO.svelte';
import { page } from '$app/state';
const locale = getLocale();
const canonicalUrl = `https://aronhohmann.eu${page.url.pathname}`;
const personJsonLd = {
'@context': 'https://schema.org',
'@type': 'Person',
name: 'Aron August Hohmann',
url: 'https://aronhohmann.eu',
image: 'https://aronhohmann.eu/images/aron_august_hohmann.avif',
jobTitle: 'Business Analyst & Solution Designer',
worksFor: {
'@type': 'Organization',
name: 'Holzkern Time for Nature GmbH'
},
address: {
'@type': 'PostalAddress',
addressLocality: 'Vienna',
addressCountry: 'AT'
},
sameAs: [
'https://www.linkedin.com/in/aron-august-hohmann/',
'https://aronhohmann.eu'
]
};
let { data } = $props();
</script>
<SEO
title={m.meta_blog_title()}
description={m.meta_blog_description()}
type="website"
{canonicalUrl}
jsonLd={personJsonLd}
/>
<div class="max-w-2xl mx-auto px-4 py-12">
<h1 class="text-3xl font-bold mb-8">Blog</h1>
@ -16,7 +51,7 @@
<li class="py-6">
<a href={`/${getLocale()}/blog/${post.slug}`} class="group block">
<p class="text-sm text-brand/80">{post.date}</p>
<h2 class="text-xl font-semibold group-hover:text-[#156793] transition">{post.title}</h2>
<h2 class="text-xl font-semibold group-hover:text-brand transition">{post.title}</h2>
<p class="text-gray-600">{post.description}</p>
</a>
</li>

View file

@ -1,14 +1,51 @@
<script lang="ts">
import { m } from '\$lib/paraglide/messages.js';
import SEO from '$lib/components/SEO.svelte';
import { page } from '$app/state';
let { data } = $props();
const { metadata, content: Content } = data;
import { m } from '\$lib/paraglide/messages.js';
const canonicalUrl = `https://aronhohmann.eu${page.url.pathname}`;
const blogPostingJsonLd = {
'@context': 'https://schema.org',
'@type': 'BlogPosting',
headline: metadata.title,
description: metadata.description,
datePublished: metadata.date,
url: canonicalUrl,
inLanguage: metadata.lang,
author: {
'@type': 'Person',
name: 'Aron August Hohmann',
url: 'https://aronhohmann.eu'
},
publisher: {
'@type': 'Person',
name: 'Aron August Hohmann',
url: 'https://aronhohmann.eu'
},
...(metadata.tags && { keywords: metadata.tags.join(', ') })
};
</script>
<SEO
title={metadata.title}
description={metadata.description}
type="article"
{canonicalUrl}
article={{
publishedTime: metadata.date,
tags: metadata.tags
}}
jsonLd={blogPostingJsonLd}
/>
<div class="max-w-2xl mx-auto px-4 py-12">
<a href="/blog" class="text-sm text-[#156793] hover:text-[#0f4f70] transition mb-8 block">{ m.back() }</a>
<a href="/blog" class="text-sm text-brand hover:text-[#0f4f70] transition mb-8 block">{ m.back() }</a>
<h1 class="text-4xl font-bold mb-2">{data.metadata.title}</h1>
<p class="text-gray-400 text-sm mb-8">{data.metadata.date}</p>

View file

@ -1,6 +1,34 @@
<script lang="ts">
import { m } from '$lib/paraglide/messages.js';
const email = atob('bWFpbEBhcm9uaG9obWFubi5ldQ==');
import { getLocale } from '$lib/paraglide/runtime';
import SEO from '$lib/components/SEO.svelte';
import { page } from '$app/state';
const locale = getLocale();
const canonicalUrl = `https://aronhohmann.eu${page.url.pathname}`;
const personJsonLd = {
'@context': 'https://schema.org',
'@type': 'Person',
name: 'Aron August Hohmann',
url: 'https://aronhohmann.eu',
image: 'https://aronhohmann.eu/images/aron_august_hohmann.avif',
jobTitle: 'Business Analyst & Solution Designer',
worksFor: {
'@type': 'Organization',
name: 'Holzkern Time for Nature GmbH'
},
address: {
'@type': 'PostalAddress',
addressLocality: 'Vienna',
addressCountry: 'AT'
},
sameAs: [
'https://www.linkedin.com/in/aron-august-hohmann/',
'https://aronhohmann.eu'
]
};
import { siMastodon, siGithub, siXing } from 'simple-icons';
@ -14,8 +42,17 @@
},
{ icon: siXing, label: 'Xing', href: 'https://www.xing.com/profile/AronAugust_Hohmann', handle: 'AronAugust_Hohmann' },
];
</script>
<SEO
title={m.meta_contact_title()}
description={m.meta_contact_description()}
type="website"
{canonicalUrl}
jsonLd={personJsonLd}
/>
<div class="max-w-3xl mx-auto px-4 py-16">
<h1 class="text-3xl font-bold mb-10">{m.contact_heading()}</h1>