admin widget zu dokploy geswitched, viele übersetzungen im Frontend vervollständigt und Anlässe-Seiten mit ChatGPT ausgebaut

This commit is contained in:
Codex Agent
2025-11-19 13:12:35 +01:00
parent 125c624588
commit d8f365ddd6
30 changed files with 2820 additions and 293 deletions

View File

@@ -14,6 +14,7 @@ interface PostSummary {
slug: string;
title: string;
excerpt?: string;
excerpt_html?: string;
featured_image?: string;
published_at?: string;
author?: { name?: string } | string;
@@ -34,6 +35,18 @@ interface Props {
};
}
const MarkdownPreview: React.FC<{ html?: string; fallback?: string; className?: string }> = ({ html, fallback, className }) => {
if (html && html.trim().length > 0) {
return <div className={className} dangerouslySetInnerHTML={{ __html: html }} />;
}
if (!fallback) {
return null;
}
return <p className={className}>{fallback}</p>;
};
const Blog: React.FC<Props> = ({ posts }) => {
const { localizedPath } = useLocalizedRoutes();
const { props } = usePage<{ supportedLocales?: string[] }>();
@@ -118,6 +131,7 @@ const Blog: React.FC<Props> = ({ posts }) => {
<div className="flex flex-wrap justify-center gap-2">
{posts.links.map((link, index) => {
const href = resolvePaginationHref(link.url);
const labelText = link.label?.trim() || '…';
if (!href) {
return (
@@ -126,8 +140,9 @@ const Blog: React.FC<Props> = ({ posts }) => {
variant={link.active ? 'default' : 'outline'}
disabled
className={link.active ? 'bg-[#FFB6C1] hover:bg-[#FF69B4]' : ''}
dangerouslySetInnerHTML={{ __html: link.label }}
/>
>
{labelText}
</Button>
);
}
@@ -138,7 +153,9 @@ const Blog: React.FC<Props> = ({ posts }) => {
variant={link.active ? 'default' : 'outline'}
className={link.active ? 'bg-[#FFB6C1] hover:bg-[#FF69B4]' : ''}
>
<Link href={href} dangerouslySetInnerHTML={{ __html: link.label }} />
<Link href={href} aria-label={labelText}>
{labelText}
</Link>
</Button>
);
})}
@@ -182,9 +199,11 @@ const Blog: React.FC<Props> = ({ posts }) => {
<h2 className="text-3xl font-bold text-gray-900 dark:text-gray-50">
{featuredPost.title || 'Untitled'}
</h2>
<p className="text-lg leading-relaxed text-gray-600 dark:text-gray-300">
{featuredPost.excerpt || ''}
</p>
<MarkdownPreview
html={featuredPost.excerpt_html}
fallback={featuredPost.excerpt}
className="text-lg leading-relaxed text-gray-600 dark:text-gray-300"
/>
{renderPostMeta(featuredPost)}
<Button asChild size="lg" className="bg-[#FFB6C1] hover:bg-[#FF69B4] text-white">
<Link href={buildArticleHref(featuredPost.slug)}>
@@ -224,9 +243,11 @@ const Blog: React.FC<Props> = ({ posts }) => {
<h3 className="text-xl font-semibold text-gray-900 dark:text-gray-50">
{post.title || 'Untitled'}
</h3>
<p className="text-sm leading-relaxed text-gray-600 dark:text-gray-300">
{post.excerpt || ''}
</p>
<MarkdownPreview
html={post.excerpt_html}
fallback={post.excerpt}
className="text-sm leading-relaxed text-gray-600 dark:text-gray-300"
/>
</div>
<div className="flex-1" />
{renderPostMeta(post)}
@@ -261,7 +282,11 @@ const Blog: React.FC<Props> = ({ posts }) => {
<h3 className="text-2xl font-semibold text-gray-900 dark:text-gray-50">
{post.title || 'Untitled'}
</h3>
<p className="text-gray-600 dark:text-gray-300">{post.excerpt || ''}</p>
<MarkdownPreview
html={post.excerpt_html}
fallback={post.excerpt}
className="text-gray-600 dark:text-gray-300"
/>
{renderPostMeta(post)}
<Button asChild variant="outline" className="w-fit border-pink-200 text-pink-600 hover:bg-pink-50 dark:border-pink-500/40 dark:text-pink-200">
<Link href={buildArticleHref(post.slug)}>
@@ -283,18 +308,18 @@ const Blog: React.FC<Props> = ({ posts }) => {
<MarketingLayout title={t('blog.title')}>
<Head title={t('blog.title')} />
<section className="bg-gradient-to-br from-pink-50 via-white to-amber-50 px-4 py-14 dark:from-gray-950 dark:via-gray-900 dark:to-gray-950">
<div className="container mx-auto max-w-4xl space-y-6 text-center">
<section className="bg-gradient-to-br from-pink-50 via-white to-amber-50 px-4 py-10 dark:from-gray-950 dark:via-gray-900 dark:to-gray-950 md:py-12">
<div className="container mx-auto max-w-3xl space-y-5 text-center">
<Badge variant="outline" className="border-pink-200 text-pink-600 dark:border-pink-500/50 dark:text-pink-200">
Fotospiel Blog
</Badge>
<h1 className="text-4xl font-bold text-gray-900 dark:text-gray-50 md:text-5xl">{t('blog.hero_title')}</h1>
<p className="text-lg leading-relaxed text-gray-600 dark:text-gray-300">{t('blog.hero_description')}</p>
<div className="flex flex-wrap justify-center gap-3">
<Button asChild size="lg" className="bg-[#FFB6C1] hover:bg-[#FF69B4] text-white">
<h1 className="text-3xl font-bold text-gray-900 dark:text-gray-50 md:text-4xl">{t('blog.hero_title')}</h1>
<p className="text-base leading-relaxed text-gray-600 dark:text-gray-300 md:text-lg">{t('blog.hero_description')}</p>
<div className="flex flex-wrap justify-center gap-2.5">
<Button asChild className="bg-[#FFB6C1] hover:bg-[#FF69B4] text-white px-6 py-2.5 text-base">
<Link href={localizedPath('/packages')}>{t('home.cta_explore')}</Link>
</Button>
<Button asChild size="lg" variant="outline" className="border-gray-300 text-gray-800 hover:bg-gray-100 dark:border-gray-700 dark:text-gray-50 dark:hover:bg-gray-800">
<Button asChild variant="outline" className="border-gray-300 text-gray-800 hover:bg-gray-100 px-6 py-2.5 text-base dark:border-gray-700 dark:text-gray-50 dark:hover:bg-gray-800">
<Link href="#articles">{t('blog.hero_cta')}</Link>
</Button>
</div>