Update homepage layout to a more modern grid-based design
Refactors the homepage layout from a carousel to a grid. Adjusts article slicing for new rows and removes carousel functionality. Introduces `MediumCard` component. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 517dfa7b-26ac-463d-a6e1-a58c6df97188 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: ceeb2a24-be77-456c-acfb-2e395f4b9d34 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/517dfa7b-26ac-463d-a6e1-a58c6df97188/0ZGabQy Replit-Helium-Checkpoint-Created: true
This commit is contained in:
parent
861f5bd2bc
commit
5c92bc69c8
BIN
attached_assets/image_1772314714413.png
Normal file
BIN
attached_assets/image_1772314714413.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 538 KiB |
BIN
attached_assets/image_1772314762863.png
Normal file
BIN
attached_assets/image_1772314762863.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 464 KiB |
@ -252,66 +252,16 @@ function TopStoriesList({ articles }: { articles: Article[] }) {
|
||||
}
|
||||
|
||||
function FeaturedCarousel({ articles, popular, galleryImages, focalPoints }: { articles: Article[]; popular?: Article[]; galleryImages?: GalleryImage[]; focalPoints?: Record<string, { x: number; y: number }> }) {
|
||||
const hasGallery = galleryImages && galleryImages.length > 0;
|
||||
const articlePages = Math.min(5, Math.max(1, articles.length));
|
||||
const total = articlePages + (hasGallery ? 1 : 0);
|
||||
const [page, setPage] = useState(0);
|
||||
const [paused, setPaused] = useState(false);
|
||||
|
||||
const next = useCallback(() => {
|
||||
setPage((p) => (p + 1) % total);
|
||||
}, [total]);
|
||||
|
||||
useEffect(() => {
|
||||
if (paused || total <= 1) return;
|
||||
const timer = setInterval(next, 8000);
|
||||
return () => clearInterval(timer);
|
||||
}, [paused, next, total]);
|
||||
|
||||
const isGalleryPage = hasGallery && page === total - 1;
|
||||
const isWidePage = page === 1;
|
||||
|
||||
let hero: Article | null = null;
|
||||
let side: Article[] = [];
|
||||
|
||||
if (!isGalleryPage && articles.length > 0) {
|
||||
hero = articles[page % articles.length];
|
||||
}
|
||||
|
||||
if (articles.length > 0) {
|
||||
const offset = isGalleryPage ? 0 : 1;
|
||||
side = [
|
||||
articles[(page + offset) % articles.length],
|
||||
articles[(page + offset + 1) % articles.length],
|
||||
];
|
||||
}
|
||||
const featured = articles.slice(0, 3);
|
||||
|
||||
return (
|
||||
<section data-testid="featured-carousel" onMouseEnter={() => setPaused(true)} onMouseLeave={() => setPaused(false)}>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-8 gap-4 lg:max-h-[420px]">
|
||||
<div className="lg:col-span-3 lg:h-[420px]">
|
||||
{isGalleryPage && galleryImages ? (
|
||||
<GalleryHeroCard images={galleryImages.slice(0, 30)} />
|
||||
) : hero ? (
|
||||
<HeroCard article={hero} focalPoints={focalPoints} />
|
||||
) : null}
|
||||
</div>
|
||||
<div className="lg:col-span-3 grid grid-cols-1 gap-3 grid-rows-2 lg:h-[420px]">
|
||||
{side.map((a) => (
|
||||
<SideCard key={a.id} article={a} focalPoints={focalPoints} />
|
||||
))}
|
||||
</div>
|
||||
<div className="lg:col-span-2 lg:h-[420px]">
|
||||
{popular && popular.length > 0 && <TopStoriesList articles={popular} />}
|
||||
</div>
|
||||
<section data-testid="featured-carousel">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{featured.map((a) => (
|
||||
<MediumCard key={a.id} article={a} focalPoints={focalPoints} />
|
||||
))}
|
||||
{popular && popular.length > 0 && <TopStoriesList articles={popular} />}
|
||||
</div>
|
||||
{total > 1 && (
|
||||
<div className="flex justify-center gap-2 mt-3" data-testid="carousel-dots">
|
||||
{Array.from({ length: total }).map((_, i) => (
|
||||
<button key={i} onClick={() => setPage(i)} className={`w-2.5 h-2.5 rounded-full transition-all duration-300 ${i === page ? "bg-primary w-6" : "bg-muted-foreground/30 hover:bg-muted-foreground/50"}`} data-testid={`button-carousel-dot-${i}`} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@ -357,9 +307,9 @@ export default function Home() {
|
||||
);
|
||||
}
|
||||
|
||||
const row2 = articles.slice(0, 2);
|
||||
const row3 = articles.slice(2, 4);
|
||||
const remaining = articles.slice(4);
|
||||
const row2 = articles.slice(3, 5);
|
||||
const row3 = articles.slice(5, 7);
|
||||
const remaining = articles.slice(7);
|
||||
const rows: Article[][] = [];
|
||||
for (let i = 0; i < remaining.length; i += 4) {
|
||||
rows.push(remaining.slice(i, i + 4));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user