73 lines
No EOL
2.5 KiB
TypeScript
73 lines
No EOL
2.5 KiB
TypeScript
"use client";
|
||
|
||
import { useState } from "react";
|
||
|
||
import { Header } from "@/widgets/header";
|
||
import { Footer } from "@/widgets/footer";
|
||
import { useInView } from "@/shared/hooks/useInView";
|
||
import { projects } from "@/shared/config/projects/projects";
|
||
import type { Project } from "@/shared/config/projects/types";
|
||
import { ProjectModal } from "@/widgets/project-modal";
|
||
import ProjectCard from "@/components/projects/ProjectCard";
|
||
import styles from "@/static/projects/projects-page.module.css";
|
||
|
||
const ProjectsPage = () => {
|
||
const [selected, setSelected] = useState<Project | null>(null);
|
||
const [headRef, headInView] = useInView<HTMLDivElement>(0.4);
|
||
const [gridRef, gridInView] = useInView<HTMLDivElement>(0.08);
|
||
|
||
const reveal = (visible: boolean) =>
|
||
`transition-all duration-700 ease-out will-change-transform ${
|
||
visible ? "opacity-100 translate-y-0" : "opacity-0 translate-y-8"
|
||
}`;
|
||
|
||
return (
|
||
<>
|
||
<Header />
|
||
|
||
<main className="relative flex flex-col">
|
||
<section className={styles.projectsPage} data-scroll-section>
|
||
<span className={styles.glow} aria-hidden="true" />
|
||
<span className={styles.ghost} aria-hidden="true">
|
||
{String(projects.length).padStart(2, "0")}
|
||
</span>
|
||
|
||
<div className="page-container relative z-10">
|
||
<div ref={headRef} className={styles.head}>
|
||
<p className={`${styles.eyebrow} ${reveal(headInView)}`}>
|
||
<span className={styles.rule} aria-hidden="true" />
|
||
проекты
|
||
</p>
|
||
|
||
<h1 className={`${styles.title} ${reveal(headInView)}`}>
|
||
Все <span className={styles.titleAccent}>работы</span>
|
||
</h1>
|
||
|
||
<p className={`${styles.count} ${reveal(headInView)}`}>
|
||
{String(projects.length).padStart(2, "0")} проектов под ключ
|
||
</p>
|
||
</div>
|
||
|
||
<div ref={gridRef} className={styles.grid}>
|
||
{projects.map((project, index) => (
|
||
<div
|
||
key={project.id}
|
||
className={reveal(gridInView)}
|
||
style={{ transitionDelay: `${index * 60}ms` }}
|
||
>
|
||
<ProjectCard project={project} onOpen={setSelected} />
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<ProjectModal project={selected} onClose={() => setSelected(null)} />
|
||
</section>
|
||
</main>
|
||
|
||
<Footer />
|
||
</>
|
||
);
|
||
};
|
||
|
||
export default ProjectsPage; |