+
+ {article.title}
+
-
-
-
- {article.author}
-
-
-
- {format(new Date(article.publishedAt), "d. MMMM yyyy", { locale: de })}
-
-
-
- {article.views.toLocaleString()} Aufrufe
-
+
+
+
+ {article.author}
+
+
+
+ {format(new Date(article.publishedAt), "d. MMMM yyyy", { locale: de })}
+
+
+
+ {article.views.toLocaleString()} Aufrufe
+
+
+
+
+
+
-
+ {(() => {
+ 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 (
+
{
+ 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");
+ }
+ });
+ }}>
+
+
+
+
+ );
+ })()}
+
+
+
+
-
- {(() => {
- 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 (
-
{
- 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");
- }
- });
- }}>
-
-
-
-
- );
- })()}
-
-
-
-
-
-
diff --git a/replit.md b/replit.md
index 97661ad..6619a24 100644
--- a/replit.md
+++ b/replit.md
@@ -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)