Naslovnica: mobilni mozaik (2 mali + 1 siroka, nato 1 velika + 2 mali), desktop nespremenjen
This commit is contained in:
parent
3c6079d720
commit
6f4cfa8ee9
@ -148,6 +148,77 @@ function getObjectPosition(coverImage: string | null, focalPoints?: Record<strin
|
|||||||
return `${fp.x}% ${fp.y}%`;
|
return `${fp.x}% ${fp.y}%`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function MosaicTile({ article, focalPoints, tall = false }: { article: Article; focalPoints?: Record<string, { x: number; y: number }>; tall?: boolean }) {
|
||||||
|
const objPos = getObjectPosition(article.coverImage, focalPoints);
|
||||||
|
return (
|
||||||
|
<Link href={`/article/${article.slug}`}>
|
||||||
|
<div className="relative rounded-lg overflow-hidden" data-testid={`tile-mosaic-${article.id}`}>
|
||||||
|
<img
|
||||||
|
src={thumbUrl(article.coverImage)}
|
||||||
|
alt={article.title}
|
||||||
|
className={`w-full object-cover ${tall ? "aspect-[16/10]" : "aspect-square"}`}
|
||||||
|
style={{ objectPosition: objPos }}
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-t from-black/85 via-black/30 to-transparent" />
|
||||||
|
<span className="absolute top-2 left-2 bg-primary text-white text-[10px] font-semibold px-2 py-0.5 rounded">
|
||||||
|
{article.category || "News"}
|
||||||
|
</span>
|
||||||
|
<h3 className={`absolute bottom-2 left-2 right-2 text-white font-semibold leading-snug ${tall ? "text-base line-clamp-2" : "text-xs line-clamp-3"}`}>
|
||||||
|
{article.title}
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function MosaicHeading({ children }: { children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<div className="mb-3">
|
||||||
|
<h2 className="text-primary font-bold text-lg leading-none mb-2">{children}</h2>
|
||||||
|
<div className="h-0.5 w-16 bg-primary" />
|
||||||
|
<div className="h-px w-full bg-card-border -mt-px" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function MobileMosaic({ latest, popular, focalPoints }: { latest: Article[]; popular?: Article[]; focalPoints?: Record<string, { x: number; y: number }> }) {
|
||||||
|
const l = (latest || []).slice(0, 3);
|
||||||
|
if (l.length === 0) return null;
|
||||||
|
const p = (popular || []).filter((a) => !l.some((x) => x.id === a.id)).slice(0, 3);
|
||||||
|
return (
|
||||||
|
<div className="md:hidden space-y-6" data-testid="section-mobile-mosaic">
|
||||||
|
<section>
|
||||||
|
<MosaicHeading>Neueste Artikel</MosaicHeading>
|
||||||
|
<div className="grid grid-cols-2 gap-2">
|
||||||
|
{l.slice(0, 2).map((a) => (
|
||||||
|
<MosaicTile key={a.id} article={a} focalPoints={focalPoints} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
{l[2] && (
|
||||||
|
<div className="mt-2">
|
||||||
|
<MosaicTile article={l[2]} focalPoints={focalPoints} tall />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{p.length > 0 && (
|
||||||
|
<section>
|
||||||
|
<MosaicHeading>Beliebt</MosaicHeading>
|
||||||
|
<MosaicTile article={p[0]} focalPoints={focalPoints} tall />
|
||||||
|
{p.length > 1 && (
|
||||||
|
<div className="grid grid-cols-2 gap-2 mt-2">
|
||||||
|
{p.slice(1, 3).map((a) => (
|
||||||
|
<MosaicTile key={a.id} article={a} focalPoints={focalPoints} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function MediumCard({ article, focalPoints }: { article: Article; focalPoints?: Record<string, { x: number; y: number }> }) {
|
function MediumCard({ article, focalPoints }: { article: Article; focalPoints?: Record<string, { x: number; y: number }> }) {
|
||||||
const isVideo = article.category === "Video";
|
const isVideo = article.category === "Video";
|
||||||
const objPos = getObjectPosition(article.coverImage, focalPoints);
|
const objPos = getObjectPosition(article.coverImage, focalPoints);
|
||||||
@ -707,7 +778,14 @@ export default function Home() {
|
|||||||
|
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-4 gap-4">
|
<div className="grid grid-cols-1 lg:grid-cols-4 gap-4">
|
||||||
<div className="lg:col-span-3 space-y-4">
|
<div className="lg:col-span-3 space-y-4">
|
||||||
<FeaturedCarousel articles={articles.filter(a => a.featured)} popular={popular} galleryImages={galleryImages} focalPoints={focalPoints} />
|
<div className="hidden md:block">
|
||||||
|
<FeaturedCarousel articles={articles.filter(a => a.featured)} popular={popular} galleryImages={galleryImages} focalPoints={focalPoints} />
|
||||||
|
</div>
|
||||||
|
<MobileMosaic
|
||||||
|
latest={[...articles].sort((a, b) => new Date(b.publishedAt).getTime() - new Date(a.publishedAt).getTime())}
|
||||||
|
popular={popular}
|
||||||
|
focalPoints={focalPoints}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="lg:col-span-1 space-y-4">
|
<div className="lg:col-span-1 space-y-4">
|
||||||
<SidebarWeatherWidget />
|
<SidebarWeatherWidget />
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user