Skip to content

Commit

Permalink
✨ Implement structured JSON-LD data for QuizHead, FAQ, and Quiz listi…
Browse files Browse the repository at this point in the history
…ng pages to enhance SEO and accessibility. Update metadata generation with dynamic content and improve question answer formatting for better clarity. This refactor ensures consistent structured data across the application.
  • Loading branch information
Malte2036 committed Jan 22, 2025
1 parent eb31084 commit ce57e48
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 9 deletions.
55 changes: 54 additions & 1 deletion src/lib/quiz/QuizHead.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import type { ExtendedQuestion, QuestionType } from '$lib/model/question';
import { version } from '$app/environment';
export let questionType: QuestionType;
export let question: ExtendedQuestion | undefined;
Expand Down Expand Up @@ -43,11 +44,60 @@
if (question) {
return `THW Prüfungsfragen – ${getFriendlyType()}, Frage ${question.number}: ${
question.text
}. Antworten: ${Array.from(question.answers.values()).join(', ')}.`;
}. Antworten: ${Array.from(
question.answers.map((a, index) => `${index + 1}: ${a.text}`).values()
).join(', ')}.`;
} else {
return getGenericDescription();
}
}
$: jsonLd = question
? {
'@context': 'https://schema.org',
'@type': 'WebPage',
name: getTitle(),
description: getDescription(),
inLanguage: 'de',
dateModified: new Date(+version).toISOString(),
mainEntity: {
'@type': 'Question',
name: question.text,
text: question.text,
suggestedAnswer: question.answers.map((answer, index) => ({
'@type': 'Answer',
text: answer.text,
position: index + 1
}))
},
about: {
'@type': 'Thing',
name: getFriendlyType(),
description: getGenericDescription()
},
audience: {
'@type': 'Audience',
audienceType: 'THW Volunteers',
description: 'Ehrenamtliche Helferinnen und Helfer im Technischen Hilfswerk'
},
isPartOf: {
'@type': 'WebSite',
name: 'THW-Tools',
url: `https://thw-tools.de/quiz/${questionType}/listing`
},
publisher: {
'@type': 'Organization',
name: 'THW-Tools',
url: 'https://thw-tools.de',
logo: {
'@type': 'ImageObject',
url: 'https://thw-tools.de/_app/immutable/assets/thw-mzgw.24176eee.webp',
width: '512',
height: '512'
}
}
}
: undefined;
</script>

<svelte:head>
Expand All @@ -71,4 +121,7 @@
name="keywords"
content="THW, THW Prüfungsfragen, Grundausbildung, Atemschutz, CBRN, Sprechfunk, Online-Quiz, Theorie-Quiz, Prüfung, THW-Tools, Feuerwehr, Ausbildung, Training"
/>
{#if jsonLd}
{@html `<script type="application/ld+json">${JSON.stringify(jsonLd)}</script>`}
{/if}
</svelte:head>
11 changes: 3 additions & 8 deletions src/routes/(main)/faq/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import InstallPwaDialog from '$lib/InstallPWADialog.svelte';
import FeedbackDialog from '$lib/FeedbackDialog.svelte';
import { version } from '$app/environment';
import { formatDate } from '$lib/utils';
export let data: PageData;
Expand All @@ -20,20 +21,14 @@
$: jsonLd = {
'@context': 'https://schema.org',
'@type': 'FAQPage',
name: 'THW-Tools FAQ',
description:
'Häufig gestellte Fragen zu THW-Tools: Prüfungsfragen, Finnentest, Spannungsfall und mehr',
url: 'https://thw-tools.de/faq',
inLanguage: 'de',
dateModified: version,
dateModified: new Date(+version).toISOString().split('T')[0],
mainEntity: data.faqs.map((faq) => ({
'@type': 'Question',
name: faq.question,
acceptedAnswer: {
'@type': 'Answer',
text: faq.text.replace(/\{\{link\}\}/g, ''),
url:
'https://thw-tools.de/faq#faq-' + faq.question.toLowerCase().replace(/[^a-z0-9]+/g, '-')
text: faq.text.replace(/\{\{link\}\}/g, '')
}
})),
publisher: {
Expand Down
38 changes: 38 additions & 0 deletions src/routes/(main)/quiz/[type]/listing/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import QuestionsStatistics from '$lib/quiz/question/QuestionsStatistics.svelte';
import { getQuestionStatsCountForType } from '$lib/api/api';
import { getQuizTypeName } from '$lib/quiz/quizUtils';
import { version } from '$app/environment';
export let data: PageData;
Expand Down Expand Up @@ -41,10 +42,47 @@
return `Das Quiz besteht aus ${count} Fragen für die Ausbildung im Technischen Hilfswerk.`;
}
}
$: jsonLd = {
'@context': 'https://schema.org',
'@type': 'ItemList',
name: getQuizTypeName(data.questionType),
description: getDescriptionForQuestionType(data.questionType),
inLanguage: 'de',
dateModified: new Date(+version).toISOString(),
numberOfItems: data.allQuestions.length,
itemListElement: data.allQuestions
.slice(0, 50) // Limit to first 50 items for better performance
.map((question, index) => ({
'@type': 'ListItem',
position: index + 1,
url: `https://thw-tools.de/quiz/${data.questionType}/${question.number}`
})),
about: {
'@type': 'Thing',
name: getQuizTypeName(data.questionType),
description: getDescriptionForQuestionType(data.questionType)
},
publisher: {
'@type': 'Organization',
name: 'THW-Tools',
url: 'https://thw-tools.de',
logo: {
'@type': 'ImageObject',
url: 'https://thw-tools.de/_app/immutable/assets/thw-mzgw.24176eee.webp',
width: '512',
height: '512'
}
}
};
</script>

<QuizHead questionType={data.questionType} question={undefined} />

<svelte:head>
{@html `<script type="application/ld+json">${JSON.stringify(jsonLd)}</script>`}
</svelte:head>

<div class="flex flex-col gap-8 px-4 py-8">
<header class="text-center">
<h1 class="text-3xl font-bold mb-4">{getQuizTypeName(data.questionType)}</h1>
Expand Down

0 comments on commit ce57e48

Please # to comment.