'use client'; // Превращаем компонент в клиентский import Link from "next/link"; import React, { useEffect, useState } from "react"; import { allProjects } from "contentlayer/generated"; import { Navigation } from "../components/nav"; import { Card } from "../components/card"; import { Article } from "./article"; import { Eye } from "lucide-react"; export const revalidate = 60; type ViewsData = Record; export default function ProjectsPage() { const [views, setViews] = useState({}); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); // Загружаем данные через клиентский запрос useEffect(() => { const fetchViews = async () => { try { const response = await fetch('/api/views'); if (!response.ok) throw new Error('Failed to fetch views'); const data = await response.json(); setViews(data); } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error'); } finally { setLoading(false); } }; fetchViews(); }, []); const featured = allProjects.find((project) => project.slug === "cbg")!; const top2 = allProjects.find((project) => project.slug === "blog")!; const top3 = allProjects.find((project) => project.slug === "bimkaspace")!; const sorted = allProjects .filter((p) => p.published) .filter( (project) => project.slug !== featured.slug && project.slug !== top2.slug && project.slug !== top3.slug, ) .sort( (a, b) => new Date(b.date ?? Number.POSITIVE_INFINITY).getTime() - new Date(a.date ?? Number.POSITIVE_INFINITY).getTime(), ); return (

Проекты

Часть проектов делал из академического интереса, часть мои проекты для себя.

{featured.date ? ( ) : ( SOON )}
{" "} {Intl.NumberFormat("en-US", { notation: "compact" }).format( views[featured.slug] ?? 0, )}

{featured.title}

{featured.description}

Подробнее

{[top2, top3].map((project) => (
))}
{sorted .filter((_, i) => i % 3 === 0) .map((project) => (
))}
{sorted .filter((_, i) => i % 3 === 1) .map((project) => (
))}
{sorted .filter((_, i) => i % 3 === 2) .map((project) => (
))}
); }