This commit is contained in:
2025-01-09 00:40:28 +03:00
parent 860ba978a2
commit df505ff51d
52 changed files with 1261 additions and 120 deletions

View File

@ -0,0 +1,21 @@
import React from 'react';
import Image from "next/image";
interface Props {
className?: string;
imageUrl: string;
}
const AvatarImage: React.FC<Props> =({ imageUrl, className}) => {
return(
<Image
src={`/images/${imageUrl}.png`}
alt={imageUrl}
className={`${className} relative`}
width={67}
height={67}
/>
);
}
export default AvatarImage;

37
components/breadcrumb.tsx Normal file
View File

@ -0,0 +1,37 @@
"use client";
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import React from 'react';
const Breadcrumbs: React.FC = () => {
const pathname = usePathname();
const pathSegments = pathname.split('/').filter(segment => segment);
const correctName = {
events: "мероприятия сообщества",
event: "базовая программа подготовки гештальт-терапевтов - добор",
participants: "участники",
id: "кириллов кирилл кириллович"
}
return(
<nav className="max-w-[1032px] mx-auto">
<ol className="flex text-middleGrey font-[350] my-[50px]">
<li>
<Link href="/">главная</Link>
</li>
{pathSegments.map((segment, index) => {
const href = '/' + pathSegments.slice(0, index + 1).join('/');
return (
<li key={href}>
<Link href={href}><span className="mx-[2px]">/</span>{correctName[decodeURIComponent(segment) as keyof typeof correctName]}</Link>
</li>
);
})}
</ol>
</nav>
)
}
export default Breadcrumbs;

34
components/button.tsx Normal file
View File

@ -0,0 +1,34 @@
'use client';
import * as React from 'react';
interface Props {
className?: string;
name: string;
variant?: 'default' | 'secondary';
size?: 'default';
}
const Button: React.FC<Props> = ({ className, name, variant = 'default', size = 'default' }) => {
const baseClasses = 'flex items-center justify-center whitespace-nowrap rounded-[6px] font-[400]';
const variantClasses = {
default: 'bg-blue text-[16px] text-white',
secondary: 'text-[16px] text-blue border-[1px] border-blue',
};
const sizeClasses = {
default: 'max-h-[39px] px-[25px] py-[10px]',
};
const selectedVariantClasses = variantClasses[variant] || variantClasses.default;
const selectedSizeClasses = sizeClasses[size] || sizeClasses.default;
return (
<button className={`${baseClasses} ${selectedVariantClasses} ${selectedSizeClasses} ${className}`}>
{name}
</button>
);
}
export default Button;

23
components/event-card.tsx Normal file
View File

@ -0,0 +1,23 @@
import React from 'react';
import Image from "next/image";
import Link from "next/link";
interface Props {
title: string;
description: string;
image?: string;
}
const EventCard: React.FC<Props> = ({title, description, image}) => {
return (
<Link href="events/event" className="border-[1px] border-white rounded-[6px] bg-darkGrey px-[13.5px] pt-[12px] pb-[35px] text-black">
{image ? <Image src={image} alt='image' width={288} height={177} /> :
<span className="flex w-[288px] h-[177px] bg-white"/>
}
<h5 className="max-w-[267px] font-[500] text-[16px] leading-[18px] mt-[30px] mb-[8px] line-clamp-3 text-ellipsis">{title}</h5>
<p className="max-w-[267px] text-[15px] leading-[17px] line-clamp-3 text-ellipsis">{description}</p>
</Link>
);
}
export default EventCard;

View File

@ -0,0 +1,25 @@
"use client";
import React, { useState } from 'react';
const FilterCheckbox: React.FC = () => {
const [active, setActive] = useState(false);
const handleCheckboxChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setActive(event.target.checked);
};
return (
<label className="flex items-center text-[14px] text-lightGrey gap-[12px]">
<input
className="w-[16px] h-[16px] border-white"
type="checkbox"
checked={active}
onChange={handleCheckboxChange}
/>
только мероприятия Донецкого сообщества
</label>
);
}
export default FilterCheckbox;

28
components/footer.tsx Normal file
View File

@ -0,0 +1,28 @@
import React from 'react';
import Image from "next/image";
import SocialItem from "@/components/social-item";
import Link from 'next/link';
const Footer: React.FC = () => {
return (
<footer className="container pb-8 px-8 m-auto flex justify-center mt-[80px]">
<a href="/public">
<Image width={150} height={48} src="/logo.svg" alt="logo"/>
</a>
<div className="flex gap-[96px] text-[15px] text-dark ml-[108px] mr-[188px] items-center font-[350]">
<Link href="/events">События</Link>
<Link href="/participants">Участники</Link>
</div>
<div className="flex gap-[25px]">
<Image width={83} height={21} src="/images/oppgp.svg" alt="oop"/>
<Image width={96} height={27} src="/images/pmg.svg" alt="pmg"/>
</div>
<div className="flex ml-[49px] gap-[29px]">
<SocialItem icon="logo_tg" link=""/>
<SocialItem icon="logo_vk" link=""/>
</div>
</footer>
);
}
export default Footer;

24
components/header.tsx Normal file
View File

@ -0,0 +1,24 @@
import React from 'react';
import Image from "next/image";
import SocialItem from "@/components/social-item";
import Link from 'next/link';
const Header: React.FC = () => {
return (
<header className="flex pt-8 px-8 justify-center items-center container m-auto">
<div className="flex gap-[96px] text-[15px] text-dark mr-[220px] font-[350]">
<Link href="/events">События</Link>
<Link href="/participants">Участники</Link>
</div>
<Link href="/">
<Image width={150} height={48} src="/logo.svg" alt="logo" />
</Link>
<div className="flex ml-[340px] gap-[19px]">
<SocialItem icon="logo_tg" link=""/>
<SocialItem icon="logo_vk" link=""/>
</div>
</header>
);
};
export default Header;

77
components/human-card.tsx Normal file
View File

@ -0,0 +1,77 @@
import React from 'react';
import Image from "next/image";
import InfoItem from "@/components/info-item";
import Link from "next/link";
interface Props {
name: string;
description?: string;
skills: string[];
post?: string;
image?: string;
variant?: 'default' | 'secondary' | 'lg';
}
const HumanCard: React.FC<Props> = ({name, description, image, skills,post, variant = 'default'}) => {
const cardStyles = {
default: {
main: "",
img: {
w: 221,
h: 221
},
name: "text-[18px]",
},
secondary: {
main: "flex w-full justify-between",
img: {
w: 218,
h: 232
}
},
lg: {
main: "",
img: {
w: 280,
h: 280
},
name: "text-[20px]",
}
};
return (
<Link href="/participants/id" className={`${cardStyles[variant].main} backdrop-blur-custom border-[1px] border-white rounded-[6px] bg-darkWhite p-[10px] text-black w-fit shadow-custom`}>
{image ? <Image src={image} alt='image' width={cardStyles[variant].img.w} height={cardStyles[variant].img.h} /> :
<Image src="/images/mok_human.svg" alt='image' width={cardStyles[variant].img.w} height={cardStyles[variant].img.h} className="rotate-[180deg]" />
}
{(variant === 'default' || variant === 'lg') &&
<>
<h5 className={`${cardStyles[variant].name} font-[400] leading-[20px] max-w-[190px] mt-[16px] mb-[20px]`}>{name}</h5>
<span className="text-lightGrey">
Работает с темами
<p className="text-black text-[13px] leading-[15px] line-clamp-3 text-ellipsis max-w-[220px] mb-[16px]">{description}</p>
</span>
<div className="flex gap-[5px] max-w-[220px] flex-wrap">
{skills.map((skill, index) => {
return <InfoItem name={skill} key={index} />
})}
</div>
</>
}
{variant === 'secondary' &&
<div className="flex flex-col ml-[16px]">
<h5 className="font-[400] text-[21px] leading-[25px] max-w-[204px] mt-[8px] mb-[18px]">{name}</h5>
<span className="text-[15px] text-lightGrey mb-[55px]">{post}</span>
<div className="flex gap-[7px] max-w-[220px] flex-wrap">
{skills.map((skill, index) => {
return <InfoItem name={skill} key={index} variable="white"/>
})}
</div>
</div>
}
</Link>
);
}
export default HumanCard;

13
components/info-block.tsx Normal file
View File

@ -0,0 +1,13 @@
import React from 'react';
import Image from "next/image";
const InfoBlock: React.FC = () => {
return (
<div className="flex bg-blue rounded-[25px] relative max-w-[1032px] w-full m-auto pt-[58px] pb-[61px] pl-[69px] h-[234px]">
<p className="text-white text-[32px] max-w-[671px] font-[500]">Через собственное развитие мы развиваем и популяризируем гештальт-подход</p>
<Image className="absolute right-[39px] top-[-20px]" src="/images/palm.svg" alt="palm" width={217} height={254} />
</div>
);
};
export default InfoBlock;

30
components/info-item.tsx Normal file
View File

@ -0,0 +1,30 @@
import React from 'react';
import Image from "next/image";
interface Props {
name: string;
variable?: 'default' | 'lg' | 'secondary' | 'white' | 'lgFixed' | 'whiteFixed';
pathImg?: string;
}
const InfoItem: React.FC<Props> = ({name, variable = 'default', pathImg}) => {
const variantClasses = {
default: 'text-[9px] py-[4px] px-[8px] rounded-[3px] border-[0.5px] text-blue',
secondary: 'text-[16px] text-lightBlack border-[1px] rounded-[6px] py-[10px] px-[28px] gap-[10px]',
lg: 'px-[10px] py-[6.5px] rounded-[6px] border-[1px] text-[16px] text-blue',
lgFixed: 'px-[10px] py-[6.5px] max-w-[140px] w-full rounded-[6px] border-[1px] text-[16px] text-blue',
white: 'text-[10px] py-[9px] px-[16px] text-blue bg-white rounded-[6px]',
whiteFixed: 'tex-[14px] rounded-[6px] max-w-[114px] w-full bg-white py-[5px] text-blue'
};
const selectedVariantClasses = variantClasses[variable] || variantClasses.default;
return (
<span className={`flex items-center justify-center font-[400] border-blue w-fit ${selectedVariantClasses}`}>
{pathImg && <Image src={`/images/${pathImg}.svg`} alt={pathImg} width={18} height={18} />}
{name}
</span>
);
}
export default InfoItem

View File

@ -0,0 +1,22 @@
import React from 'react';
import InfoItem from "@/components/info-item";
import SectionItem from "@/components/section-item";
const NavSection: React.FC= () => {
const navigations : string[] = ["конференции", "акредитации", "открытые сертификации", "открытые сертификации", "общие сборы", "протоколы сборов", "новости сайта", "календарь событий", "сайт мги", "вопросы и ответы"]
return (
<div className="flex gap-[53px] items-end m-auto">
<div className="flex max-w-[645px] flex-wrap gap-x-[15px] gap-y-[12px]">
{navigations.map((nav, index) => {
return <InfoItem name={nav} key={index} variable="lg" />
})}
</div>
<div className="flex gap-[19px]">
<SectionItem name="Книги" />
<SectionItem name="лекции" />
</div>
</div>
);
}
export default NavSection

83
components/pagination.tsx Normal file
View File

@ -0,0 +1,83 @@
import React from 'react';
import Image from "next/image";
interface PaginationProps {
totalItems: number;
itemsPerPage: number;
currentPage: number;
onPageChange: (page: number) => void;
}
const Pagination: React.FC<PaginationProps> = ({
totalItems,
itemsPerPage,
currentPage,
onPageChange,
}) => {
const totalPages = Math.ceil(totalItems / itemsPerPage);
const getPaginationArray = () => {
const pages: (number | string)[] = [];
if (totalPages <= 5) {
for (let i = 1; i <= totalPages; i++) {
pages.push(i);
}
} else {
pages.push(1);
if (currentPage > 3) {
pages.push('...');
}
for (let i = Math.max(2, currentPage - 1); i <= Math.min(currentPage + 1, totalPages - 1); i++) {
pages.push(i);
}
if (currentPage < totalPages - 2) {
pages.push('...');
}
pages.push(totalPages);
}
return pages;
};
const handlePageChange = (page: number) => {
if (page !== currentPage) {
onPageChange(page);
}
};
const paginationArray = getPaginationArray();
return (
<div className="flex">
<button className="mr-[30px]" onClick={() => handlePageChange(currentPage - 1)} disabled={currentPage === 1}>
<Image className="rotate-[90deg] relative top-[-2px]" src="/images/chevronDown.svg" alt="arrow" width={11} height={11} />
</button>
<div className="flex gap-[12px] items-center">
{paginationArray.map((page, index) => (
typeof page === 'number' ? (
<button
key={index}
onClick={() => handlePageChange(page)}
className={currentPage === page ? 'text-blue font-[700] text-[17px]' : 'text-[17px]'}
>
{page}
</button>
) : (
<span key={index}>{page}</span> // Отображаем многоточие
)
))}
</div>
<button className="flex items-center text-[15px] font-[400] ml-[26px] gap-[11px]" onClick={() => handlePageChange(currentPage + 1)} disabled={currentPage === totalPages}>
Следующая страница
<Image className="rotate-[-90deg] relative top-[-2px]" src="/images/chevronDown.svg" alt="arrow" width={11} height={11} />
</button>
</div>
);
};
export default Pagination;

View File

@ -0,0 +1,17 @@
import React from 'react';
import Image from "next/image";
interface Props {
name: string;
}
const SectionItem: React.FC<Props> = ({name}) => {
return (
<div className="flex border-[4px] border-white rounded-[6px] items-center w-[160px] h-[120px] justify-center relative">
<Image className="absolute top-[-18px]" src="/images/chevronDown.svg" alt="arrow" width={11} height={11} />
<span className="text-[26px] text-black uppercase">{name}</span>
</div>
);
}
export default SectionItem

26
components/select.tsx Normal file
View File

@ -0,0 +1,26 @@
'use client';
import * as React from 'react';
import Image from "next/image";
interface Props {
className?: string;
name: string;
variant?: 'default' | 'secondary';
}
const Select: React.FC<Props> = ({className, name, variant = 'default'}) => {
const variantClasses = {
default: 'px-[25px] py-[10px]',
secondary: 'px-[36px] py-[7px] bg-white',
};
return(
<div className={`${className} ${variantClasses[variant]} w-fit cursor-pointer border-blue border-[1px] flex gap-[10px] rounded-[10px]`}>
<p className="text-blue font-[400] text-[16px]">{name}</p>
<Image src="/images/chevronDown.svg" alt="chevronDown" width={11} height={8} />
</div>
);
}
export default Select

View File

@ -0,0 +1,16 @@
import React from 'react';
import Image from "next/image";
interface Props {
icon: string;
link: string;
}
const SocialItem: React.FC<Props> = ({icon, link}) => {
return (
<a className="flex justify-center items-center w-[41px] h-[41px] bg-blue rounded-full" href="">
<Image src={`/images/${icon}.svg`} alt={icon} className="w-auto h-auto" width={1} height={1} /> </a>
);
}
export default SocialItem