diff --git a/attached_assets/image_1772301812509.png b/attached_assets/image_1772301812509.png new file mode 100644 index 0000000..2e9c874 Binary files /dev/null and b/attached_assets/image_1772301812509.png differ diff --git a/client/src/pages/home.tsx b/client/src/pages/home.tsx index 69353d8..6d80a63 100644 --- a/client/src/pages/home.tsx +++ b/client/src/pages/home.tsx @@ -3,219 +3,197 @@ import { Link } from "wouter"; import { type Article } from "@shared/schema"; import { format } from "date-fns"; import { de } from "date-fns/locale"; -import { Eye, Clock } from "lucide-react"; +import { Eye, Clock, Play } from "lucide-react"; import { Skeleton } from "@/components/ui/skeleton"; -import { Button } from "@/components/ui/button"; import Header from "@/components/header"; import Footer from "@/components/footer"; -import { ArticleCardAd, SidebarAd, InArticleAd } from "@/components/adsense"; +import AdSense, { ArticleCardAd } from "@/components/adsense"; import { useState, useEffect, useCallback } from "react"; -function FeaturedSection({ articles }: { articles: Article[] }) { - const pool = articles.slice(0, 9); - const totalPages = Math.ceil(pool.length / 3); - const [page, setPage] = useState(0); - const [paused, setPaused] = useState(false); - - const next = useCallback(() => { - setPage((p) => (p + 1) % totalPages); - }, [totalPages]); - - useEffect(() => { - if (paused || totalPages <= 1) return; - const timer = setInterval(next, 8000); - return () => clearInterval(timer); - }, [paused, next, totalPages]); - - if (pool.length === 0) return null; - - const start = page * 3; - const visible = pool.slice(start, start + 3); - while (visible.length < 3 && pool.length >= 3) { - visible.push(pool[visible.length % pool.length]); - } - - const hero = visible[0]; - const side = visible.slice(1, 3); - - return ( -
setPaused(true)} - onMouseLeave={() => setPaused(false)} - > -
- -
-
- {hero.title} -
-
- - {format(new Date(hero.publishedAt), "d. MMMM yyyy", { locale: de })} - -

- {hero.title} -

-

- {hero.excerpt} -

-
-
-
- - -
- {side.map((article) => ( - -
-
- {article.title} -
-
- - {format(new Date(article.publishedAt), "d. MMMM yyyy", { locale: de })} - -

- {article.title} -

-
-
-
- - ))} -
-
- - {totalPages > 1 && ( -
- {Array.from({ length: totalPages }).map((_, i) => ( -
- )} -
- ); -} - function thumbUrl(src: string | null): string { if (!src) return "/images/article-1.png"; if (src.endsWith(".webp")) return src.replace(".webp", "-thumb.webp"); return src; } -function ArticleCard({ article }: { article: Article }) { +function timeAgo(date: Date): string { + const now = new Date(); + const diffMs = now.getTime() - date.getTime(); + const diffH = Math.floor(diffMs / 3600000); + const diffD = Math.floor(diffMs / 86400000); + if (diffH < 1) return "Gerade eben"; + if (diffH < 24) return `vor ${diffH} Std.`; + if (diffD < 7) return `vor ${diffD} T.`; + return format(date, "d. MMM yyyy", { locale: de }); +} + +function HeroCard({ article }: { article: Article }) { + const isVideo = article.category === "Video"; return ( -
-
-
- {article.title} -
-
-
-
- {article.author} - · - {format(new Date(article.publishedAt), "d. MMMM yyyy", { locale: de })} -
-

- {article.title} -

-

- {article.excerpt} -

-
-
- - - {article.views.toLocaleString()} +
+ {article.title} + {isVideo && ( +
+
+ +
+
+ )} +
+
+
+ + {article.category} + + + {timeAgo(new Date(article.publishedAt))}
- +

+ {article.title} +

+

+ {article.excerpt} +

+
+ + {article.views.toLocaleString()} +
-
+ ); } -function PopularSidebar({ articles }: { articles: Article[] }) { +function MediumCard({ article }: { article: Article }) { + const isVideo = article.category === "Video"; return ( - + ); } -function ArticleCardSkeleton() { +function BentoSkeleton() { return ( -
- -
- - - - +
+
+
+
+ + + + +
); @@ -226,23 +204,54 @@ export default function Home() { queryKey: ["/api/articles"], }); - const { data: featured } = useQuery({ - queryKey: ["/api/articles/featured"], - }); - const { data: popular } = useQuery({ queryKey: ["/api/articles/popular"], }); + if (isLoading || !articles) { + return ( +
+
+
+ +
+
+
+ ); + } + + const all = articles; + const row1Hero = all[0]; + const row1Medium = all.slice(1, 3); + const row2Items = all.slice(3, 6); + const row3Items = all.slice(6); + return (
-
- {featured && featured.length > 0 && ( - +
+ + {row1Hero && ( +
+
+ +
+ +
+ {row1Medium.map((a) => ( + + ))} +
+ +
+ {popular && popular.length > 0 && ( + + )} +
+
)} -
+
-
-
- {isLoading ? ( -
- {Array.from({ length: 4 }).map((_, i) => ( - - ))} -
- ) : ( -
- {(articles || []).flatMap((article, index) => { - const items = [ - , - ]; - if (index === 1) { - items.push(); - } - if (index === 4) { - items.push(); - } - return items; - })} -
- )} + {row2Items.length > 0 && ( +
+ {row2Items.map((a) => ( + + ))} +
+ )} -
- {popular && popular.length > 0 && ( - - )} - + {row3Items.length > 0 && ( +
+
+ {row3Items[0] && } +
+
+ {row3Items.slice(1, 3).map((a) => ( + + ))} + {row3Items.slice(3).map((a) => ( + + ))} + +
-
+ )} +