Adjust article layout to position side ads closer to content
Modify article page layout to reduce side ad width and remove unnecessary wrapper div. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 23852c00-4779-460a-9e0c-d09fee4b6c92 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 26960b3d-c70e-43b9-a359-aab3199ecab7 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/23852c00-4779-460a-9e0c-d09fee4b6c92/MkhYNq3 Replit-Helium-Checkpoint-Created: true
This commit is contained in:
parent
25f31c0867
commit
4b77ed8935
@ -219,115 +219,113 @@ export default function ArticlePage() {
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
<Header />
|
||||
<PageSideAds />
|
||||
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<Link href="/">
|
||||
<Button variant="ghost" size="sm" className="mb-3 gap-2" data-testid="button-back">
|
||||
<ArrowLeft className="w-4 h-4" />
|
||||
Zurück
|
||||
</Button>
|
||||
</Link>
|
||||
<PageSideAds contentHalfWidth={480} />
|
||||
<main className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
||||
<Link href="/">
|
||||
<Button variant="ghost" size="sm" className="mb-3 gap-2" data-testid="button-back">
|
||||
<ArrowLeft className="w-4 h-4" />
|
||||
Zurück
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
{article.coverImage && (
|
||||
<div className="relative overflow-hidden rounded-md mb-5 max-h-[420px]">
|
||||
<img
|
||||
src={article.coverImage}
|
||||
alt={article.title}
|
||||
className="w-full h-full object-cover"
|
||||
style={{ maxHeight: "420px" }}
|
||||
data-testid="img-article-cover"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/40 to-transparent" />
|
||||
</div>
|
||||
)}
|
||||
{article.coverImage && (
|
||||
<div className="relative overflow-hidden rounded-md mb-5 max-h-[420px]">
|
||||
<img
|
||||
src={article.coverImage}
|
||||
alt={article.title}
|
||||
className="w-full h-full object-cover"
|
||||
style={{ maxHeight: "420px" }}
|
||||
data-testid="img-article-cover"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/40 to-transparent" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mb-5">
|
||||
<h1
|
||||
className="text-2xl md:text-3xl font-bold text-foreground mb-3 leading-tight"
|
||||
data-testid="text-article-title"
|
||||
>
|
||||
{article.title}
|
||||
</h1>
|
||||
<div className="mb-5">
|
||||
<h1
|
||||
className="text-2xl md:text-3xl font-bold text-foreground mb-3 leading-tight"
|
||||
data-testid="text-article-title"
|
||||
>
|
||||
{article.title}
|
||||
</h1>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-3 text-xs text-muted-foreground">
|
||||
<span className="flex items-center gap-1.5">
|
||||
<User className="w-3.5 h-3.5" />
|
||||
{article.author}
|
||||
</span>
|
||||
<span className="flex items-center gap-1.5">
|
||||
<Calendar className="w-3.5 h-3.5" />
|
||||
{format(new Date(article.publishedAt), "d. MMMM yyyy", { locale: de })}
|
||||
</span>
|
||||
<span className="flex items-center gap-1.5">
|
||||
<Eye className="w-3.5 h-3.5" />
|
||||
{article.views.toLocaleString()} Aufrufe
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="mt-3">
|
||||
<ShareButtons
|
||||
url={`${window.location.origin}/article/${article.slug}`}
|
||||
title={article.title}
|
||||
image={article.coverImage ? (article.coverImage.startsWith("http") ? article.coverImage : `${window.location.origin}${article.coverImage}`) : undefined}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-3 text-xs text-muted-foreground">
|
||||
<span className="flex items-center gap-1.5">
|
||||
<User className="w-3.5 h-3.5" />
|
||||
{article.author}
|
||||
</span>
|
||||
<span className="flex items-center gap-1.5">
|
||||
<Calendar className="w-3.5 h-3.5" />
|
||||
{format(new Date(article.publishedAt), "d. MMMM yyyy", { locale: de })}
|
||||
</span>
|
||||
<span className="flex items-center gap-1.5">
|
||||
<Eye className="w-3.5 h-3.5" />
|
||||
{article.views.toLocaleString()} Aufrufe
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{(() => {
|
||||
const sanitized = sanitizeContent(article.content);
|
||||
const blocks = sanitized.split(/(?=<(?:p|h[2-4]|div)[\s>])/i).filter(Boolean);
|
||||
const midPoint = Math.max(2, Math.floor(blocks.length / 2));
|
||||
const firstHalf = blocks.slice(0, midPoint).join("");
|
||||
const secondHalf = blocks.slice(midPoint).join("");
|
||||
const proseClasses = `prose prose-base dark:prose-invert max-w-none
|
||||
prose-headings:text-foreground prose-headings:font-semibold prose-headings:text-lg
|
||||
prose-p:text-foreground/85 prose-p:leading-relaxed prose-p:text-[15px]
|
||||
prose-a:text-primary prose-a:no-underline hover:prose-a:underline
|
||||
prose-strong:text-foreground
|
||||
prose-img:rounded-md prose-img:w-full prose-img:object-cover
|
||||
[&_iframe]:rounded-md [&_iframe]:my-5 [&_iframe]:max-w-full
|
||||
[&_div[style]]:flex [&_div[style]]:justify-center
|
||||
[&_blockquote:not(.instagram-media)]:border-l-primary [&_blockquote:not(.instagram-media)]:bg-accent/50 [&_blockquote:not(.instagram-media)]:rounded-r-md [&_blockquote:not(.instagram-media)]:py-1
|
||||
[&_.instagram-media]:!bg-transparent [&_.instagram-media]:!border-0 [&_.instagram-media]:!shadow-none [&_.instagram-media]:!p-0 [&_.instagram-media]:mx-auto`;
|
||||
return (
|
||||
<div ref={(el) => {
|
||||
if (!el) return;
|
||||
el.querySelectorAll("a[href]").forEach((a) => {
|
||||
const href = a.getAttribute("href") || "";
|
||||
const isBunny = href.includes("mediadelivery.net") || href.includes("bunny.net") || href.includes("b-cdn.net");
|
||||
const isInternal = href.startsWith("/") || href.includes("folx.tv");
|
||||
if (!isBunny && !isInternal && href.startsWith("http")) {
|
||||
a.setAttribute("target", "_blank");
|
||||
a.setAttribute("rel", "noopener noreferrer");
|
||||
}
|
||||
});
|
||||
}}>
|
||||
<article
|
||||
className={proseClasses}
|
||||
dangerouslySetInnerHTML={{ __html: firstHalf }}
|
||||
data-testid="article-content"
|
||||
/>
|
||||
<InArticleAd />
|
||||
<article
|
||||
className={proseClasses}
|
||||
dangerouslySetInnerHTML={{ __html: secondHalf }}
|
||||
data-testid="article-content-continued"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
|
||||
<div className="mt-6 pt-5 border-t border-border">
|
||||
<div className="mt-3">
|
||||
<ShareButtons
|
||||
url={`${window.location.origin}/article/${article.slug}`}
|
||||
title={article.title}
|
||||
image={article.coverImage ? (article.coverImage.startsWith("http") ? article.coverImage : `${window.location.origin}${article.coverImage}`) : undefined}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<RelatedArticles currentSlug={slug || ""} />
|
||||
</div>
|
||||
|
||||
{(() => {
|
||||
const sanitized = sanitizeContent(article.content);
|
||||
const blocks = sanitized.split(/(?=<(?:p|h[2-4]|div)[\s>])/i).filter(Boolean);
|
||||
const midPoint = Math.max(2, Math.floor(blocks.length / 2));
|
||||
const firstHalf = blocks.slice(0, midPoint).join("");
|
||||
const secondHalf = blocks.slice(midPoint).join("");
|
||||
const proseClasses = `prose prose-base dark:prose-invert max-w-none
|
||||
prose-headings:text-foreground prose-headings:font-semibold prose-headings:text-lg
|
||||
prose-p:text-foreground/85 prose-p:leading-relaxed prose-p:text-[15px]
|
||||
prose-a:text-primary prose-a:no-underline hover:prose-a:underline
|
||||
prose-strong:text-foreground
|
||||
prose-img:rounded-md prose-img:w-full prose-img:object-cover
|
||||
[&_iframe]:rounded-md [&_iframe]:my-5 [&_iframe]:max-w-full
|
||||
[&_div[style]]:flex [&_div[style]]:justify-center
|
||||
[&_blockquote:not(.instagram-media)]:border-l-primary [&_blockquote:not(.instagram-media)]:bg-accent/50 [&_blockquote:not(.instagram-media)]:rounded-r-md [&_blockquote:not(.instagram-media)]:py-1
|
||||
[&_.instagram-media]:!bg-transparent [&_.instagram-media]:!border-0 [&_.instagram-media]:!shadow-none [&_.instagram-media]:!p-0 [&_.instagram-media]:mx-auto`;
|
||||
return (
|
||||
<div ref={(el) => {
|
||||
if (!el) return;
|
||||
el.querySelectorAll("a[href]").forEach((a) => {
|
||||
const href = a.getAttribute("href") || "";
|
||||
const isBunny = href.includes("mediadelivery.net") || href.includes("bunny.net") || href.includes("b-cdn.net");
|
||||
const isInternal = href.startsWith("/") || href.includes("folx.tv");
|
||||
if (!isBunny && !isInternal && href.startsWith("http")) {
|
||||
a.setAttribute("target", "_blank");
|
||||
a.setAttribute("rel", "noopener noreferrer");
|
||||
}
|
||||
});
|
||||
}}>
|
||||
<article
|
||||
className={proseClasses}
|
||||
dangerouslySetInnerHTML={{ __html: firstHalf }}
|
||||
data-testid="article-content"
|
||||
/>
|
||||
<InArticleAd />
|
||||
<article
|
||||
className={proseClasses}
|
||||
dangerouslySetInnerHTML={{ __html: secondHalf }}
|
||||
data-testid="article-content-continued"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
|
||||
<div className="mt-6 pt-5 border-t border-border">
|
||||
<ShareButtons
|
||||
url={`${window.location.origin}/article/${article.slug}`}
|
||||
title={article.title}
|
||||
image={article.coverImage ? (article.coverImage.startsWith("http") ? article.coverImage : `${window.location.origin}${article.coverImage}`) : undefined}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<RelatedArticles currentSlug={slug || ""} />
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user