diff --git a/next.config.mjs b/next.config.mjs index 3182a51..0058348 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,6 +1,6 @@ /** @type {import('next').NextConfig} */ const nextConfig = { - output: "export", + // output: "export", trailingSlash: true, distDir: "dist", }; diff --git a/src/Projects/DesktopProjects.tsx b/src/Projects/DesktopProjects.tsx new file mode 100644 index 0000000..1cb324d --- /dev/null +++ b/src/Projects/DesktopProjects.tsx @@ -0,0 +1,36 @@ +import { Fragment } from "react"; +import ProjectsSection from "@components/ProjectsSection"; +import { IProject } from "../types/IProject"; +import { SortedProject } from "../types/SortedProject"; + +interface IProjectsProps { + projects: IProject[]; + projectLabels: (string | number)[]; + sortedProjects: SortedProject | undefined; +} + +const DesktopProjects = ({ + projects, + projectLabels, + sortedProjects, +}: IProjectsProps) => { + return ( +
+ {projectLabels.map((year) => { + const projects = (sortedProjects && sortedProjects.get(year)) ?? []; + + return ( + + {projects.length !== 0 && ( +
+ +
+ )} +
+ ); + })} +
+ ); +}; + +export default DesktopProjects; diff --git a/src/Projects/MobileProjects.tsx b/src/Projects/MobileProjects.tsx new file mode 100644 index 0000000..296f9ba --- /dev/null +++ b/src/Projects/MobileProjects.tsx @@ -0,0 +1,70 @@ +import { Fragment, useEffect, useLayoutEffect, useState } from "react"; +import MoreProjectButton from "@components/MoreProjectButton"; +import ProjectCard from "@components/ProjectCard"; +import { IProject } from "../types/IProject"; +import { SortedProject } from "../types/SortedProject"; +import LabelCard from "@components/LabelCart"; +import { getTime, getYear } from "date-fns"; + +interface IProjectsProps { + projects: IProject[]; + projectLabels: (string | number)[]; + sortedProjects: SortedProject | undefined; +} + +const MobileProjects = ({ sortedProjects }: IProjectsProps) => { + const [currentCount, setCurrentCount] = useState(5); + const [projects, setProjects] = useState([]); + let previosLabel: string | number = ""; + + useLayoutEffect(() => { + if (!sortedProjects) return; + + const _projects = []; + const values = Array.from(sortedProjects.values()); + for (let i = 0; i < values.length; i++) { + const pr = values[i]; + for (let j = 0; j < pr.length; j++) { + _projects.push(pr[j]); + } + } + + setProjects(_projects); + }, [sortedProjects]); + + const handleShowMore = () => { + setCurrentCount((prev) => prev + 8); + }; + + return ( +
+ {projects.slice(0, currentCount).map((project, index) => { + const projectYear = getYear(project.releaseDate); + const label = project.stage !== 6 ? "В работе" : projectYear; + const projects = sortedProjects?.get(projectYear); + if (previosLabel === "") { + previosLabel = label; + } + + if ((index === 0 || previosLabel !== label) && projects?.length !== 0) { + previosLabel = label; + return ( + <> + {/*
*/} + + + + ); + } + + return ; + })} + + {projects.length > currentCount && ( + + )} +
+ ); +}; + +export default MobileProjects; diff --git a/src/Projects/Projects.tsx b/src/Projects/Projects.tsx new file mode 100644 index 0000000..631caf6 --- /dev/null +++ b/src/Projects/Projects.tsx @@ -0,0 +1,53 @@ +import { useState, useEffect } from "react"; +import Heading2 from "../components/Headings/Heading2"; +import { IProject } from "../types/IProject"; +import { SortedProject } from "../types/SortedProject"; +import DesktopProjects from "./DesktopProjects"; +import MobileProjects from "./MobileProjects"; +import api from "@utils/api"; +import { getProjectLabels } from "../calc/getProjectLabels"; +import { getSortedProjects } from "../calc/getSortedProjects"; + +const Projects = () => { + const [projects, setProjects] = useState([]); + const [projectLabels, setProjectLabels] = useState<(string | number)[]>([]); + const [sortedProjects, setSortedProjects] = useState(); + + async function getProjects() { + try { + const _projects: IProject[] = await api.get("projects").json(); + const _projectLabels = getProjectLabels(_projects); + const _sortedProjects = getSortedProjects(_projects); + + setProjectLabels(_projectLabels); + setSortedProjects(_sortedProjects); + setProjects(_projects); + } catch (error) { + if (error instanceof Error) { + alert(`Error: ${error.message}`); + } + } + } + + useEffect(() => { + getProjects(); + }, []); + + return ( +
+ Проекты + + +
+ ); +}; + +export default Projects; diff --git a/src/app/page.tsx b/src/app/page.tsx index 081ef97..515c758 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -35,6 +35,7 @@ import { motion } from "framer-motion"; import { Video } from "../types/Video"; import Reviews from "@components/Reviews"; import Histories from "@components/Histories"; +import Projects from "../Projects/Projects"; const VIDEOS_FEATURES: Video[] = [ { @@ -99,56 +100,13 @@ const VIDEOS_FEATURES: Video[] = [ }, ]; -function getSortedProjects(projects: IProject[]) { - const sorted = [...projects].sort( - (da, db) => getTime(db.releaseDate) - getTime(da.releaseDate) - ); - - const sortedProject: SortedProject = new Map(); - - for (let i = 0; i < sorted.length; i++) { - const project = sorted[i]; - const projectYear = getYear(project.releaseDate); - const key = project.stage !== 6 ? "В работе" : projectYear; - - if (sortedProject.has(key)) { - const prevProjects = sortedProject.get(key) as IProject[]; - const updatedProjects = [...prevProjects, project]; - sortedProject.set(key, updatedProjects); - } else { - const createdProjects = [project]; - sortedProject.set(key, createdProjects); - } - } - - return sortedProject; -} - -function getProjectLabels(projects: IProject[]) { - const projectYears: number[] = []; - - for (let i = 0; i < projects.length; i++) { - const project = getYear(projects[i].releaseDate); - if (projectYears.includes(project)) continue; - projectYears.push(project); - } - - projectYears.sort((a, b) => b - a); - - const projectLabels = ["В работе", ...projectYears]; - - return projectLabels; -} - export default function App() { const [selectedVideo, setSelectedVideo] = useState( "/videos/features/virtual_tour.mp4" ); - const [projects, setProjects] = useState([]); - const [projectLabels, setProjectLabels] = useState<(string | number)[]>([]); - const [sortedProjects, setSortedProjects] = useState(); + const [setModal] = useModalStore((state) => [state.setModal]); - const [isShownAllProjects, setIsShownAllProjects] = useState(false); + const [isBuffering, setIsBuffering] = useState(true); const [isViewportEntered, setIsViewportEntered] = useState(false); @@ -158,26 +116,6 @@ export default function App() { setIsViewportEntered(true); }; - async function getProjects() { - try { - const _projects: IProject[] = await api.get("projects").json(); - const _projectLabels = getProjectLabels(_projects); - const _sortedProjects = getSortedProjects(_projects); - - setProjectLabels(_projectLabels); - setSortedProjects(_sortedProjects); - setProjects(_projects); - } catch (error) { - if (error instanceof Error) { - alert(`Error: ${error.message}`); - } - } - } - - useEffect(() => { - getProjects(); - }, []); - return (
@@ -674,45 +612,7 @@ export default function App() { - -
- Проекты -
- {projectLabels.map((year) => { - const projects = - (sortedProjects && sortedProjects.get(year)) ?? []; - - return ( - - {projects.length !== 0 && ( -
- -
- )} -
- ); - })} -
-
- {[...Array.from({ length: 5 })].map((_, index) => ( - - ))} - {!isShownAllProjects ? ( - setIsShownAllProjects(true)} - /> - ) : ( - <> - {projects.map( - (_, index) => - projects[index + 5] && ( - - ) - )} - - )} -
-
+
diff --git a/src/calc/getProjectLabels.ts b/src/calc/getProjectLabels.ts new file mode 100644 index 0000000..9df5515 --- /dev/null +++ b/src/calc/getProjectLabels.ts @@ -0,0 +1,20 @@ +import { getYear } from "date-fns"; +import { IProject } from "../types/IProject"; + +function getProjectLabels(projects: IProject[]) { + const projectYears: number[] = []; + + for (let i = 0; i < projects.length; i++) { + const year = getYear(projects[i].releaseDate); + if (projectYears.includes(year)) continue; + projectYears.push(year); + } + + projectYears.sort((a, b) => b - a); + + const projectLabels = ["В работе", ...projectYears]; + + return projectLabels; +} + +export { getProjectLabels }; diff --git a/src/calc/getSortedProjects.ts b/src/calc/getSortedProjects.ts new file mode 100644 index 0000000..1b32e60 --- /dev/null +++ b/src/calc/getSortedProjects.ts @@ -0,0 +1,30 @@ +import { getTime, getYear } from "date-fns"; +import { IProject } from "../types/IProject"; +import { SortedProject } from "../types/SortedProject"; + +function getSortedProjects(projects: IProject[]) { + const sorted = [...projects].sort( + (da, db) => getTime(db.releaseDate) - getTime(da.releaseDate) + ); + + const sortedProject: SortedProject = new Map(); + + for (let i = 0; i < sorted.length; i++) { + const project = sorted[i]; + const projectYear = getYear(project.releaseDate); + const key = project.stage !== 6 ? "В работе" : projectYear; + + if (sortedProject.has(key)) { + const prevProjects = sortedProject.get(key) as IProject[]; + const updatedProjects = [...prevProjects, project]; + sortedProject.set(key, updatedProjects); + } else { + const createdProjects = [project]; + sortedProject.set(key, createdProjects); + } + } + + return sortedProject; +} + +export { getSortedProjects }; diff --git a/src/components/CardYear.tsx b/src/components/LabelCart.tsx similarity index 66% rename from src/components/CardYear.tsx rename to src/components/LabelCart.tsx index e974e76..19f6bcd 100644 --- a/src/components/CardYear.tsx +++ b/src/components/LabelCart.tsx @@ -3,7 +3,7 @@ interface LabelCardProps { } const LabelCard = ({ label }: LabelCardProps): JSX.Element => { - return
{label}
; + return
{label}
; }; export default LabelCard; diff --git a/src/components/MoreProjectButton.tsx b/src/components/MoreProjectButton.tsx index 8188dee..d99a92c 100644 --- a/src/components/MoreProjectButton.tsx +++ b/src/components/MoreProjectButton.tsx @@ -13,7 +13,7 @@ function MoreProjectButton({ onClick }: IMoreProjectButtonProps) { whileInView={{ opacity: 1 }} viewport={{ once: true, margin: "-100px" }} transition={{ duration: 1, ease: [0.58, 0.12, 0.27, 0.98], delay: 0.2 }} - className="border border-[#3D425C] p-4 flex sm:flex-col sm:justify-end items-end gap-2 sm:rounded-none rounded-full" + className="border border-[#3D425C] p-4 flex sm:flex-col sm:justify-end items-end gap-2 sm:rounded-none rounded-full aspect-square" onClick={onClick} >
diff --git a/src/components/ProjectsSection.tsx b/src/components/ProjectsSection.tsx index cc2de75..4419f56 100644 --- a/src/components/ProjectsSection.tsx +++ b/src/components/ProjectsSection.tsx @@ -1,5 +1,5 @@ import { IProject } from "../types/IProject"; -import LabelCard from "./CardYear"; +import LabelCard from "./LabelCart"; import ProjectCard from "./ProjectCard"; type ProjectYearSectionProps = { diff --git a/src/types/IProject.ts b/src/types/IProject.ts index df4f3ee..a6dfa79 100644 --- a/src/types/IProject.ts +++ b/src/types/IProject.ts @@ -1,7 +1,7 @@ import Device from "./Device"; interface IProject { - id?: string; + id: string; name: string; company: string; city: string; @@ -11,4 +11,4 @@ interface IProject { devices: Device[]; } -export type {IProject}; +export type { IProject };