Improve article page readability and appearance on desktop
Adjust article page layout on desktop, reducing image size, title font size, and text size while narrowing content width for better readability and visual balance. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 23852c00-4779-460a-9e0c-d09fee4b6c92 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: a2ee97c2-94c0-42af-9ffb-1551048efa6a Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/23852c00-4779-460a-9e0c-d09fee4b6c92/BvOHMz7 Replit-Helium-Checkpoint-Created: true
This commit is contained in:
parent
0df13503b8
commit
d13867d660
@ -221,110 +221,113 @@ export default function ArticlePage() {
|
||||
<Header />
|
||||
<PageSideAds />
|
||||
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
||||
<Link href="/">
|
||||
<Button variant="ghost" size="sm" className="mb-4 gap-2" data-testid="button-back">
|
||||
<ArrowLeft className="w-4 h-4" />
|
||||
Zurück
|
||||
</Button>
|
||||
</Link>
|
||||
<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>
|
||||
|
||||
{article.coverImage && (
|
||||
<div className="relative overflow-hidden rounded-md mb-6">
|
||||
<img
|
||||
src={article.coverImage}
|
||||
alt={article.title}
|
||||
className="w-full aspect-video object-cover"
|
||||
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-6">
|
||||
<h1
|
||||
className="text-3xl md:text-4xl font-bold text-foreground mb-4 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-4 text-sm text-muted-foreground">
|
||||
<span className="flex items-center gap-1.5">
|
||||
<User className="w-4 h-4" />
|
||||
{article.author}
|
||||
</span>
|
||||
<span className="flex items-center gap-1.5">
|
||||
<Calendar className="w-4 h-4" />
|
||||
{format(new Date(article.publishedAt), "d. MMMM yyyy", { locale: de })}
|
||||
</span>
|
||||
<span className="flex items-center gap-1.5">
|
||||
<Eye className="w-4 h-4" />
|
||||
{article.views.toLocaleString()} Aufrufe
|
||||
</span>
|
||||
<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>
|
||||
|
||||
<div className="mt-4">
|
||||
{(() => {
|
||||
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 || ""} />
|
||||
</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-lg dark:prose-invert max-w-none
|
||||
prose-headings:text-foreground prose-headings:font-semibold
|
||||
prose-p:text-foreground/85 prose-p:leading-relaxed
|
||||
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-6 [&_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-8 pt-6 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>
|
||||
|
||||
@ -151,6 +151,14 @@ When adding new articles:
|
||||
9. Facebook embeds: copy the iframe code as-is from user
|
||||
10. After deploy, go to Facebook Sharing Debugger and click "Scrape Again" to refresh cache
|
||||
|
||||
## Article Page Layout
|
||||
- Outer wrapper: `max-w-7xl` (for PageSideAds), inner content: `max-w-4xl mx-auto`
|
||||
- Cover image: `max-h-[420px]` with object-cover
|
||||
- Title: `text-2xl md:text-3xl` font-bold
|
||||
- Meta (author/date/views): `text-xs` with `w-3.5 h-3.5` icons
|
||||
- Body text: `prose-base` with `prose-p:text-[15px]` and `prose-headings:text-lg`
|
||||
- In-article ad splits content at midpoint
|
||||
|
||||
## Important Notes
|
||||
- Tailwind `object-[center_25%]` does NOT work — must use inline `style={{ objectPosition: "center 25%" }}`
|
||||
- Horoscope widget navigates to /horoskop on click (no modal)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user