feat: update site URLs and enhance image handling
- Changed site URLs in docker-compose and deployment configurations to remove "www" prefix for consistency. - Improved image handling by introducing warmPostCardImages function for pre-fetching images in posts and tags. - Enhanced PostCard component with responsive image sizes for better performance. - Updated layout to include robots meta tag and JSON-LD structured data for improved SEO. - Added loading state for images in TopBanner component to enhance user experience.
This commit is contained in:
@@ -12,7 +12,8 @@ import {
|
||||
getPostImageField,
|
||||
formatPostDate,
|
||||
} from '$lib/blog-utils';
|
||||
import { POST_RESOLVE } from '$lib/constants';
|
||||
import { POST_RESOLVE, POST_SOCIAL_IMAGE_TRANSFORM, SITE_NAME } from '$lib/constants';
|
||||
import { env } from '$env/dynamic/public';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import { marked } from 'marked';
|
||||
|
||||
@@ -47,6 +48,21 @@ export const load: PageServerLoad = async ({ params, locals, url }) => {
|
||||
})
|
||||
: null;
|
||||
|
||||
const siteBaseUrl = (env.PUBLIC_SITE_URL || '').replace(/\/$/, '');
|
||||
const canonical = `${siteBaseUrl}/post/${slug}/`;
|
||||
const postSocialImageRel = postImageField
|
||||
? await ensureTransformedImage(postImageField.url, {
|
||||
...POST_SOCIAL_IMAGE_TRANSFORM,
|
||||
focalX: postImageField.focal?.x,
|
||||
focalY: postImageField.focal?.y,
|
||||
})
|
||||
: null;
|
||||
const postSocialImageAbs = postSocialImageRel
|
||||
? postSocialImageRel.startsWith('/')
|
||||
? `${siteBaseUrl}${postSocialImageRel}`
|
||||
: postSocialImageRel
|
||||
: null;
|
||||
|
||||
const postDate = formatPostDate(post.created);
|
||||
|
||||
const postContent = (post as { content?: string }).content;
|
||||
@@ -63,6 +79,14 @@ export const load: PageServerLoad = async ({ params, locals, url }) => {
|
||||
((post as { row2Content?: unknown[] }).row2Content?.length ?? 0) > 0 ||
|
||||
((post as { row3Content?: unknown[] }).row3Content?.length ?? 0) > 0;
|
||||
|
||||
const siteName =
|
||||
(import.meta.env.PUBLIC_SITE_NAME as string | undefined) || SITE_NAME;
|
||||
const postCreated = (post as { created?: string }).created ?? null;
|
||||
const postUpdated = (post as { updated?: string }).updated ?? postCreated;
|
||||
const postAuthor = (post as { author?: string }).author ?? null;
|
||||
const postHeadline = post.headline ?? post.linkName ?? slug;
|
||||
const postDescription = post.seoDescription ?? post.subheadline ?? post.excerpt ?? '';
|
||||
|
||||
const isEvent = !!(post as { isEvent?: boolean }).isEvent;
|
||||
const eventDateRaw = (post as { eventDate?: string }).eventDate ?? null;
|
||||
const eventDateLabel =
|
||||
@@ -104,6 +128,68 @@ export const load: PageServerLoad = async ({ params, locals, url }) => {
|
||||
.replace(/\{\{PAGE_TITLE\}\}/g, post.headline ?? post.linkName ?? slug);
|
||||
const showCommentSection = (post as { showCommentSection?: boolean }).showCommentSection !== false;
|
||||
|
||||
const jsonLd: Record<string, unknown>[] = [];
|
||||
const articleLd: Record<string, unknown> = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': isEvent ? 'Article' : 'BlogPosting',
|
||||
headline: postHeadline,
|
||||
mainEntityOfPage: { '@type': 'WebPage', '@id': canonical },
|
||||
url: canonical,
|
||||
inLanguage: 'de-DE',
|
||||
...(postDescription ? { description: postDescription } : {}),
|
||||
...(postCreated ? { datePublished: postCreated } : {}),
|
||||
...(postUpdated ? { dateModified: postUpdated } : {}),
|
||||
...(postSocialImageAbs ? { image: postSocialImageAbs } : {}),
|
||||
author: {
|
||||
'@type': postAuthor ? 'Person' : 'Organization',
|
||||
name: postAuthor ?? siteName,
|
||||
},
|
||||
publisher: {
|
||||
'@type': 'Organization',
|
||||
name: siteName,
|
||||
...(siteBaseUrl ? { url: siteBaseUrl } : {}),
|
||||
},
|
||||
};
|
||||
jsonLd.push(articleLd);
|
||||
|
||||
if (isEvent && eventDateRaw) {
|
||||
const eventLd: Record<string, unknown> = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'Event',
|
||||
name: postHeadline,
|
||||
startDate: eventDateRaw,
|
||||
eventAttendanceMode: 'https://schema.org/OfflineEventAttendanceMode',
|
||||
eventStatus: 'https://schema.org/EventScheduled',
|
||||
url: canonical,
|
||||
inLanguage: 'de-DE',
|
||||
...(postDescription ? { description: postDescription } : {}),
|
||||
...(postSocialImageAbs ? { image: postSocialImageAbs } : {}),
|
||||
organizer: {
|
||||
'@type': 'Organization',
|
||||
name: siteName,
|
||||
...(siteBaseUrl ? { url: siteBaseUrl } : {}),
|
||||
},
|
||||
...(eventLocation?.text
|
||||
? {
|
||||
location: {
|
||||
'@type': 'Place',
|
||||
name: eventLocation.text,
|
||||
...(hasCoords
|
||||
? {
|
||||
geo: {
|
||||
'@type': 'GeoCoordinates',
|
||||
latitude: eventLocation.lat,
|
||||
longitude: eventLocation.lng,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
jsonLd.push(eventLd);
|
||||
}
|
||||
|
||||
return {
|
||||
post,
|
||||
postImageUrl,
|
||||
@@ -120,9 +206,11 @@ export const load: PageServerLoad = async ({ params, locals, url }) => {
|
||||
mapLinkUrl,
|
||||
commentSlot: showCommentSection ? commentSlot : '',
|
||||
translations,
|
||||
seoTitle: post.seoTitle ?? post.headline ?? post.linkName ?? slug,
|
||||
seoDescription: post.seoDescription ?? post.subheadline ?? post.excerpt ?? '',
|
||||
socialImage: postImageUrl ?? undefined,
|
||||
seoTitle: post.seoTitle ?? postHeadline,
|
||||
seoDescription: postDescription,
|
||||
socialImage: postSocialImageAbs ?? postImageUrl ?? undefined,
|
||||
robots: (post as { seoMetaRobots?: string }).seoMetaRobots ?? undefined,
|
||||
jsonLd,
|
||||
breadcrumbItems: [
|
||||
{ href: '/', label: 'Start' },
|
||||
{ href: '/posts/', label: 'Beiträge' },
|
||||
|
||||
Reference in New Issue
Block a user