Compare commits
10 Commits
b9cafe7b2f
...
d83b077cd2
| Author | SHA1 | Date | |
|---|---|---|---|
| d83b077cd2 | |||
| 7b96acc65f | |||
| 2a7e29875c | |||
| 9bc98bd582 | |||
| 6f28b60ffd | |||
| 01b61d41b9 | |||
| 7770baa945 | |||
| 2f80489d1f | |||
| 998ca26b04 | |||
| 2560e47b11 |
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 MiB After Width: | Height: | Size: 14 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.0 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 270 KiB |
@@ -3,6 +3,7 @@ import { fluxgore } from "@/utils/fonts";
|
|||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
import { Swiper, SwiperSlide } from "swiper/react";
|
import { Swiper, SwiperSlide } from "swiper/react";
|
||||||
import type { Swiper as SwiperType } from "swiper";
|
import type { Swiper as SwiperType } from "swiper";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
import "swiper/css";
|
import "swiper/css";
|
||||||
|
|
||||||
@@ -35,7 +36,13 @@ function SwiperButton({
|
|||||||
`}
|
`}
|
||||||
aria-label={direction === "next" ? "Next slide" : "Previous slide"}
|
aria-label={direction === "next" ? "Next slide" : "Previous slide"}
|
||||||
>
|
>
|
||||||
<img src={iconPath} alt="" className={`w-4 h-4 sm:w-5 sm:h-5`} />
|
<Image
|
||||||
|
src={iconPath}
|
||||||
|
alt=""
|
||||||
|
width={20}
|
||||||
|
height={20}
|
||||||
|
className={`w-4 h-4 sm:w-5 sm:h-5`}
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -46,17 +53,24 @@ function Slide({ title, imageSrc }: { title: string; imageSrc: string }) {
|
|||||||
<h2 className={`${fluxgore.className} text-2xl sm:text-3xl lg:text-4xl text-white leading-none uppercase`}>
|
<h2 className={`${fluxgore.className} text-2xl sm:text-3xl lg:text-4xl text-white leading-none uppercase`}>
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
<img
|
<div className="w-full relative mt-4 sm:mt-7 aspect-video">
|
||||||
className="w-full h-auto object-cover mt-4 sm:mt-7"
|
<Image
|
||||||
src={imageSrc}
|
src={imageSrc}
|
||||||
alt="Slide Image"
|
alt={title}
|
||||||
/>
|
fill
|
||||||
|
className="object-cover"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<img
|
<div className="absolute top-full left-0 w-full">
|
||||||
className="absolute top-full left-0 w-full h-auto object-cover"
|
<Image
|
||||||
src="/images/activities/paper_tear.png"
|
src="/images/activities/paper_tear.png"
|
||||||
alt="Background Tear"
|
alt="Background Tear"
|
||||||
/>
|
width={400}
|
||||||
|
height={50}
|
||||||
|
className="w-full h-auto object-cover"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -146,13 +160,12 @@ function Activities() {
|
|||||||
imageSrc="/images/activities/taxi.jpg"
|
imageSrc="/images/activities/taxi.jpg"
|
||||||
/>
|
/>
|
||||||
</SwiperSlide>
|
</SwiperSlide>
|
||||||
<SwiperSlide>
|
{/* <SwiperSlide>
|
||||||
<Slide
|
<Slide
|
||||||
title="SMP Race такси"
|
title="SMP Race такси"
|
||||||
imageSrc="/images/activities/race_taxi.png"
|
imageSrc="/images/activities/race_taxi.png"
|
||||||
/>
|
/>
|
||||||
</SwiperSlide>
|
</SwiperSlide> */}
|
||||||
|
|
||||||
</Swiper>
|
</Swiper>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+89
-154
@@ -1,6 +1,7 @@
|
|||||||
/* eslint-disable @next/next/no-img-element */
|
/* eslint-disable @next/next/no-img-element */
|
||||||
import { fluxgore } from "@/utils/fonts";
|
import { fluxgore } from "@/utils/fonts";
|
||||||
import Button from "./Button";
|
import Button from "./Button";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
interface CoverHeadingProps {
|
interface CoverHeadingProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
@@ -12,13 +13,11 @@ function CoverHeading({ children, textPosition }: CoverHeadingProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<h1
|
<h1
|
||||||
className={`${fluxgore.className} text-white relative animate-fade-in-up uppercase`}
|
className={`${fluxgore.className} text-white relative uppercase`}
|
||||||
style={{
|
style={{
|
||||||
textAlign: textAlign,
|
textAlign: textAlign,
|
||||||
fontSize: "clamp(50px, 10vw, 7vw)", // Slightly smaller on all screen sizes
|
fontSize: "clamp(50px, 10vw, 7vw)", // Slightly smaller on all screen sizes
|
||||||
lineHeight: "1",
|
lineHeight: "1",
|
||||||
animationDelay: textPosition === "right" ? "0.3s" : "0.1s",
|
|
||||||
animationFillMode: "both",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Shadow layer */}
|
{/* Shadow layer */}
|
||||||
@@ -70,7 +69,7 @@ function CoverHeading({ children, textPosition }: CoverHeadingProps) {
|
|||||||
function DateBox() {
|
function DateBox() {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`${fluxgore.className} bg-white text-black px-6 py-2 inline-block text-3xl md:text-[40px] animate-bounce-in uppercase`}
|
className={`${fluxgore.className} bg-white text-black px-6 py-2 inline-block text-3xl md:text-[40px] uppercase`}
|
||||||
style={{
|
style={{
|
||||||
transform: "skewX(-15deg)",
|
transform: "skewX(-15deg)",
|
||||||
lineHeight: "1.2",
|
lineHeight: "1.2",
|
||||||
@@ -79,8 +78,6 @@ function DateBox() {
|
|||||||
drop-shadow(-2px -2px 0px rgba(0,0,0,0.3))
|
drop-shadow(-2px -2px 0px rgba(0,0,0,0.3))
|
||||||
`,
|
`,
|
||||||
border: "4px solid black",
|
border: "4px solid black",
|
||||||
animationDelay: "0.5s",
|
|
||||||
animationFillMode: "both",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ transform: "skewX(15deg)" }}>
|
<div style={{ transform: "skewX(15deg)" }}>
|
||||||
@@ -94,169 +91,107 @@ function DateBox() {
|
|||||||
|
|
||||||
function Cover() {
|
function Cover() {
|
||||||
return (
|
return (
|
||||||
<div
|
<div className="relative justify-center items-center py-36">
|
||||||
className="bg-cover bg-center bg-no-repeat relative justify-center items-center py-36 animate-fade-in"
|
{/* Background Image */}
|
||||||
style={{ backgroundImage: "url('/images/KV.png')" }}
|
<Image
|
||||||
>
|
src="/images/KV.png"
|
||||||
<div className="container mx-auto mb-24">
|
alt="Tech fest background"
|
||||||
{/* Top row with ФЕСТИВАЛЬ and date box */}
|
fill
|
||||||
<div className="flex align-center justify-center pb-7 md:hidden">
|
className="object-cover object-center hidden md:block"
|
||||||
<DateBox />
|
priority
|
||||||
</div>
|
quality={85}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* <div className="flex align-center justify-center pb-7 md:hidden">
|
<Image
|
||||||
<DateBox />
|
src="/images/KV_mobile.png"
|
||||||
</div>
|
alt="Tech fest background mobile"
|
||||||
<div className="flex flex-row items-center space-x-16">
|
fill
|
||||||
<CoverHeading>ФЕСТИВАЛЬ</CoverHeading>
|
className="object-cover object-center md:hidden"
|
||||||
<div className="hidden md:block">
|
priority
|
||||||
|
quality={85}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Content overlay */}
|
||||||
|
<div className="relative z-10">
|
||||||
|
<div className="container mx-auto mb-24">
|
||||||
|
{/* Top row with ФЕСТИВАЛЬ and date box */}
|
||||||
|
<div className="flex align-center justify-center pb-7 md:hidden">
|
||||||
<DateBox />
|
<DateBox />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<Image
|
||||||
|
src="/images/cover_text.png"
|
||||||
|
alt="Фестиваль технических видов спорта 2025"
|
||||||
|
width={768}
|
||||||
|
height={400}
|
||||||
|
className="w-full max-w-3xl mx-auto hidden md:block"
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Image
|
||||||
|
src="/images/cover_text_mobile.png"
|
||||||
|
alt="Фестиваль технических видов спорта 2025"
|
||||||
|
width={576}
|
||||||
|
height={300}
|
||||||
|
className="w-full max-w-3xl mx-auto md:hidden"
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex justify-end mt-10 md:mt-0">
|
||||||
|
<Image
|
||||||
|
src="/images/danger.png"
|
||||||
|
alt="free_entry"
|
||||||
|
width={265}
|
||||||
|
height={232}
|
||||||
|
className="w-32 md:w-40"
|
||||||
|
style={{
|
||||||
|
transform: "rotate(15deg)",
|
||||||
|
}}
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CoverHeading textPosition="right">ТЕХНИЧЕСКИХ</CoverHeading>
|
<div className="flex justify-center items-center"></div>
|
||||||
|
|
||||||
<CoverHeading>ВИДОВ СПОРТА</CoverHeading> */}
|
|
||||||
<img
|
|
||||||
src="/images/cover_text.png"
|
|
||||||
alt="Фестиваль технических видов спорта 2025"
|
|
||||||
className="w-full max-w-3xl mx-auto hidden md:block animate-slide-in-left"
|
|
||||||
style={{
|
|
||||||
animationDelay: "0.2s",
|
|
||||||
animationFillMode: "both",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<img
|
|
||||||
src="/images/cover_text_mobile.png"
|
|
||||||
alt="Фестиваль технических видов спорта 2025"
|
|
||||||
className="w-full max-w-3xl mx-auto md:hidden animate-slide-in-left"
|
|
||||||
style={{
|
|
||||||
animationDelay: "0.2s",
|
|
||||||
animationFillMode: "both",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-center items-center">
|
|
||||||
{/* <Button
|
|
||||||
onClick={() => {
|
|
||||||
window.location.href = "/about";
|
|
||||||
}}
|
|
||||||
className="animate-pulse-glow hover:animate-none transition-all duration-300 hover:scale-105"
|
|
||||||
style={{
|
|
||||||
animationDelay: "0.8s",
|
|
||||||
animationFillMode: "both",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
смотреть карту
|
|
||||||
</Button> */}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style jsx>{`
|
|
||||||
@keyframes fade-in {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fade-in-up {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(30px);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes slide-in-left {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateX(-50px);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateX(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes bounce-in {
|
|
||||||
0% {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(0.3) skewX(-15deg);
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
transform: scale(1.05) skewX(-15deg);
|
|
||||||
}
|
|
||||||
70% {
|
|
||||||
transform: scale(0.9) skewX(-15deg);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
opacity: 1;
|
|
||||||
transform: scale(1) skewX(-15deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes pulse-glow {
|
|
||||||
0%, 100% {
|
|
||||||
box-shadow: 0 0 20px rgba(255, 255, 255, 0.3);
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
box-shadow: 0 0 30px rgba(255, 255, 255, 0.6);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-fade-in {
|
|
||||||
animation: fade-in 0.8s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-fade-in-up {
|
|
||||||
animation: fade-in-up 0.6s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-slide-in-left {
|
|
||||||
animation: slide-in-left 0.8s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-bounce-in {
|
|
||||||
animation: bounce-in 0.8s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-pulse-glow {
|
|
||||||
animation: pulse-glow 2s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
`}</style>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CoverSoon() {
|
function CoverSoon() {
|
||||||
return (
|
return (
|
||||||
<div
|
<div className="relative justify-center items-center py-36">
|
||||||
className="bg-cover bg-center bg-no-repeat relative justify-center items-center py-36"
|
{/* Background Image */}
|
||||||
style={{ backgroundImage: "url('/images/KV.png')" }}
|
<Image
|
||||||
>
|
src="/images/KV.png"
|
||||||
<div className="container mx-auto max-w-5/7 mb-24">
|
alt="Tech fest background"
|
||||||
{/* Top row with ФЕСТИВАЛЬ and date box */}
|
fill
|
||||||
<div className="flex flex-row items-center space-x-16">
|
className="object-cover object-center"
|
||||||
<CoverHeading>ФЕСТИВАЛЬ</CoverHeading>
|
priority
|
||||||
<div className="hidden md:block">
|
quality={85}
|
||||||
<DateBox />
|
/>
|
||||||
|
|
||||||
|
{/* Content overlay */}
|
||||||
|
<div className="relative z-10">
|
||||||
|
<div className="container mx-auto max-w-5/7 mb-24">
|
||||||
|
{/* Top row with ФЕСТИВАЛЬ and date box */}
|
||||||
|
<div className="flex flex-row items-center space-x-16">
|
||||||
|
<CoverHeading>ФЕСТИВАЛЬ</CoverHeading>
|
||||||
|
<div className="hidden md:block">
|
||||||
|
<DateBox />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<CoverHeading textPosition="right">ТЕХНИЧЕСКИХ</CoverHeading>
|
||||||
|
|
||||||
|
<CoverHeading>ВИДОВ СПОРТА</CoverHeading>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CoverHeading textPosition="right">ТЕХНИЧЕСКИХ</CoverHeading>
|
<div className="flex justify-center items-center">
|
||||||
|
<Button disabled>скоро</Button>
|
||||||
<CoverHeading>ВИДОВ СПОРТА</CoverHeading>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex justify-center items-center">
|
|
||||||
<Button disabled>скоро</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
+31
-48
@@ -1,10 +1,10 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
/* eslint-disable @next/next/no-img-element */
|
|
||||||
import { fluxgore, gothampro } from "@/utils/fonts";
|
import { fluxgore, gothampro } from "@/utils/fonts";
|
||||||
import Button from "./Button";
|
import Button from "./Button";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
interface EventCardProps extends React.HTMLAttributes<HTMLDivElement> {
|
interface EventCardProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
image: string;
|
image: string;
|
||||||
@@ -33,12 +33,15 @@ function EventCard(props: EventCardProps) {
|
|||||||
id={props.id}
|
id={props.id}
|
||||||
className="flex flex-col md:flex-row bg-[#272727] py-5 px-2.5 md:py-5 md:px-2.5 p-4"
|
className="flex flex-col md:flex-row bg-[#272727] py-5 px-2.5 md:py-5 md:px-2.5 p-4"
|
||||||
>
|
>
|
||||||
<div className="w-full md:w-1/3 mb-4 md:mb-0">
|
<div className="w-full md:w-1/3 mb-4 md:mb-0 relative">
|
||||||
<img
|
<div className="w-full md:w-2/3 aspect-video relative">
|
||||||
className="w-full md:w-2/3 h-auto object-cover rounded"
|
<Image
|
||||||
src={props.image}
|
src={props.image}
|
||||||
alt={props.title}
|
alt={props.title}
|
||||||
/>
|
fill
|
||||||
|
className="object-cover rounded"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full md:w-1/3 mb-4 md:mb-0 md:px-4">
|
<div className="w-full md:w-1/3 mb-4 md:mb-0 md:px-4">
|
||||||
<h2
|
<h2
|
||||||
@@ -68,21 +71,30 @@ function Events() {
|
|||||||
<div
|
<div
|
||||||
id="events"
|
id="events"
|
||||||
className="bg-[#161616] relative pt-32 md:pt-64 pb-16 md:pb-32"
|
className="bg-[#161616] relative pt-32 md:pt-64 pb-16 md:pb-32"
|
||||||
style={{
|
|
||||||
backgroundImage: `url('/images/noise.svg')`,
|
|
||||||
backgroundSize: "cover",
|
|
||||||
backgroundRepeat: "repeat",
|
|
||||||
backgroundBlendMode: "overlay",
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<img
|
{/* Background noise pattern */}
|
||||||
id="yuka"
|
<Image
|
||||||
className="absolute top-0 w-full object-cover"
|
src="/images/noise.svg"
|
||||||
src="/images/events/paper_tear.png"
|
alt=""
|
||||||
alt="Paper tear"
|
fill
|
||||||
|
className="object-cover opacity-50 mix-blend-overlay"
|
||||||
|
quality={75}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="container mx-auto px-4">
|
{/* Paper tear image */}
|
||||||
|
<div className="absolute top-0 w-full">
|
||||||
|
<Image
|
||||||
|
id="yuka"
|
||||||
|
src="/images/events/paper_tear.png"
|
||||||
|
alt="Paper tear"
|
||||||
|
width={1920}
|
||||||
|
height={200}
|
||||||
|
className="w-full object-cover"
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="container mx-auto px-4 relative z-10">
|
||||||
<div className="flex flex-col md:flex-row md:justify-between space-y-6 md:space-y-0">
|
<div className="flex flex-col md:flex-row md:justify-between space-y-6 md:space-y-0">
|
||||||
<h1
|
<h1
|
||||||
className={`${fluxgore.className} text-4xl md:text-7xl text-white relative uppercase`}
|
className={`${fluxgore.className} text-4xl md:text-7xl text-white relative uppercase`}
|
||||||
@@ -185,35 +197,6 @@ function Events() {
|
|||||||
}
|
}
|
||||||
link="https://t.me/TechSportFestbot"
|
link="https://t.me/TechSportFestbot"
|
||||||
/>
|
/>
|
||||||
{/* <EventCard
|
|
||||||
disabled={true}
|
|
||||||
id="moto"
|
|
||||||
image="/events/moto.png"
|
|
||||||
title="КуБок ШОС по Мотокроссу"
|
|
||||||
description={
|
|
||||||
<>
|
|
||||||
<p>
|
|
||||||
Уникальная возможность увидеть настоящую битву моторов и
|
|
||||||
мастерства на трассе.
|
|
||||||
</p>
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Лучшие гонщики со всего мира соберутся, чтобы
|
|
||||||
продемонстрировать невероятные прыжки, головокружительные
|
|
||||||
виражи и бескомпромиссную борьбу за победу.
|
|
||||||
</p>
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Приготовьтесь к взрыву адреналина и незабываемым эмоциям, ведь
|
|
||||||
Кубок ШОС по Мотокроссу обещает стать одним из самых ярких
|
|
||||||
зрелищ фестиваля!
|
|
||||||
</p>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
link="#"
|
|
||||||
/> */}
|
|
||||||
<EventCard
|
<EventCard
|
||||||
disabled={true}
|
disabled={true}
|
||||||
image="/events/cart.png"
|
image="/events/cart.png"
|
||||||
|
|||||||
+43
-115
@@ -1,71 +1,23 @@
|
|||||||
/* eslint-disable @next/next/no-img-element */
|
/* eslint-disable @next/next/no-img-element */
|
||||||
import { gothampro } from "@/utils/fonts";
|
import { gothampro } from "@/utils/fonts";
|
||||||
import Button from "./Button";
|
import Button from "./Button";
|
||||||
import { useEffect, useRef } from "react";
|
import Image from "next/image";
|
||||||
|
|
||||||
function Info() {
|
function Info() {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
|
||||||
const elementsRef = useRef<(HTMLDivElement | null)[]>([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const observer = new IntersectionObserver(
|
|
||||||
(entries) => {
|
|
||||||
entries.forEach((entry) => {
|
|
||||||
if (entry.isIntersecting) {
|
|
||||||
entry.target.classList.add("animate-fade-in-up");
|
|
||||||
entry.target.classList.remove("opacity-0", "translate-y-8");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
{ threshold: 0.1, rootMargin: "0px 0px -50px 0px" }
|
|
||||||
);
|
|
||||||
|
|
||||||
elementsRef.current.forEach((el) => {
|
|
||||||
if (el) observer.observe(el);
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => observer.disconnect();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const addToRefs = (el: HTMLDivElement | null) => {
|
|
||||||
if (el && !elementsRef.current.includes(el)) {
|
|
||||||
elementsRef.current.push(el);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="info" className={gothampro.className}>
|
<div id="info" className={gothampro.className}>
|
||||||
<style jsx>{`
|
<div className="bg-[#161616] relative overflow-hidden px-4">
|
||||||
@keyframes fadeInUp {
|
{/* Background noise pattern */}
|
||||||
from {
|
<Image
|
||||||
opacity: 0;
|
src="/images/noise.svg"
|
||||||
transform: translateY(30px);
|
alt=""
|
||||||
}
|
fill
|
||||||
to {
|
className="object-cover opacity-50 mix-blend-overlay"
|
||||||
opacity: 1;
|
quality={75}
|
||||||
transform: translateY(0);
|
/>
|
||||||
}
|
|
||||||
}
|
|
||||||
.animate-fade-in-up {
|
|
||||||
animation: fadeInUp 0.6s ease-out forwards;
|
|
||||||
}
|
|
||||||
`}</style>
|
|
||||||
|
|
||||||
<div
|
<div className="container mx-auto pt-36 relative z-10">
|
||||||
ref={containerRef}
|
<div className="flex flex-row">
|
||||||
className="bg-[#161616] relative overflow-hidden px-4"
|
|
||||||
style={{
|
|
||||||
backgroundImage: `url('/images/noise.svg')`,
|
|
||||||
backgroundSize: "cover",
|
|
||||||
backgroundRepeat: "repeat",
|
|
||||||
backgroundBlendMode: "overlay",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="container mx-auto pt-36">
|
|
||||||
<div
|
|
||||||
ref={addToRefs}
|
|
||||||
className="flex flex-row opacity-0 translate-y-8 transition-all duration-700"
|
|
||||||
>
|
|
||||||
<div className="flex-1 basis-1/3">
|
<div className="flex-1 basis-1/3">
|
||||||
<p className="text-white opacity-60 text-sm md:text-base uppercase font-medium">
|
<p className="text-white opacity-60 text-sm md:text-base uppercase font-medium">
|
||||||
[ о нас ]
|
[ о нас ]
|
||||||
@@ -80,46 +32,21 @@ function Info() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div className="flex flex-row">
|
||||||
ref={addToRefs}
|
|
||||||
className="flex flex-row opacity-0 translate-y-8 transition-all duration-700 delay-200"
|
|
||||||
>
|
|
||||||
<div className="flex-1 basis-2/12"></div>
|
<div className="flex-1 basis-2/12"></div>
|
||||||
|
|
||||||
<div className="flex-col max-w-10/12">
|
<div className="flex-col max-w-10/12">
|
||||||
<p className="text-white text-base md:text-4xl font-normal">
|
<p className="text-white text-base md:text-4xl font-normal">
|
||||||
Организованный Департаментом спорта города Москвы и РАФ, он объединяет
|
Организованный Департаментом спорта города Москвы, он объединяет
|
||||||
фанатов скорости и семьи.
|
фанатов скорости и семьи.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div className="flex flex-row mt-8">
|
||||||
ref={addToRefs}
|
|
||||||
className="flex flex-row mt-8 opacity-0 translate-y-8 transition-all duration-700 delay-300"
|
|
||||||
>
|
|
||||||
<div className="flex-1 basis-1/3"></div>
|
|
||||||
|
|
||||||
<div className="flex-col max-w-2/3">
|
|
||||||
<p className="text-white text-base md:text-base font-normal md:max-w-2/5">
|
|
||||||
В этом году, помимо традиционной «Битвы за Москву» по дрифту,
|
|
||||||
вас ждут абсолютно новые для фестиваля соревнования:{" "}
|
|
||||||
<span className="text-[#1068B0]">
|
|
||||||
YUKA DRIVE FEST Джимхана и 12-тичасовая картинг-гонка.
|
|
||||||
</span>
|
|
||||||
А также масса активностей: выставки авто/мото, квест,
|
|
||||||
граффити-контест, детская зона и киберкафе. <br />
|
|
||||||
<br />
|
|
||||||
Благодаря новым партнерам, праздник будет еще ярче. Приходите
|
|
||||||
всей семьей и получите незабываемые впечатления!
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div className="flex flex-row mt-8">
|
||||||
ref={addToRefs}
|
|
||||||
className="flex flex-row mt-8 opacity-0 translate-y-8 transition-all duration-700 delay-500"
|
|
||||||
>
|
|
||||||
<div className="flex-1 basis-1/3"></div>
|
<div className="flex-1 basis-1/3"></div>
|
||||||
|
|
||||||
<div className="flex-col md:min-w-2/3 justify-start items-start">
|
<div className="flex-col md:min-w-2/3 justify-start items-start">
|
||||||
@@ -139,37 +66,38 @@ function Info() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="container mx-auto flex flex-col md:flex-row pt-12 md:pt-24 pb-28 md:pb-56 gap-4 md:gap-0">
|
<div className="container mx-auto flex flex-col md:flex-row pt-12 md:pt-24 pb-28 md:pb-56 gap-4 md:gap-0 relative z-10">
|
||||||
<div
|
<div className="w-full md:w-1/3 flex justify-center md:justify-start">
|
||||||
ref={addToRefs}
|
<div className="w-3/4 md:w-1/2 relative hover:scale-105 transition-transform duration-300">
|
||||||
className="w-full md:w-1/3 flex justify-center md:justify-start opacity-0 translate-y-8 transition-all duration-700 delay-700"
|
<Image
|
||||||
>
|
src="/images/info/moto.png"
|
||||||
<img
|
alt="moto"
|
||||||
src="/images/info/moto.png"
|
width={400}
|
||||||
alt="moto"
|
height={300}
|
||||||
className="w-3/4 md:w-1/2 h-auto object-cover hover:scale-105 transition-transform duration-300"
|
className="w-full h-auto object-cover"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className="w-full md:w-1/3 flex justify-center">
|
||||||
ref={addToRefs}
|
<div className="w-3/4 md:w-full relative hover:scale-105 transition-transform duration-300">
|
||||||
className="w-full md:w-1/3 flex justify-center opacity-0 translate-y-8 transition-all duration-700 delay-900"
|
<Image
|
||||||
>
|
src="/images/info/podium.jpg"
|
||||||
<img
|
alt="car"
|
||||||
src="/images/info/podium.jpg"
|
width={500}
|
||||||
alt="car"
|
height={400}
|
||||||
className="w-3/4 md:w-full h-auto object-cover hover:scale-105 transition-transform duration-300"
|
className="w-full h-auto object-cover"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className="flex w-full md:w-1/3 justify-center md:justify-start">
|
||||||
ref={addToRefs}
|
|
||||||
className="flex w-full md:w-1/3 justify-center md:justify-start opacity-0 translate-y-8 transition-all duration-700 delay-1000"
|
|
||||||
>
|
|
||||||
<div className="w-0 md:w-1/3"></div>
|
<div className="w-0 md:w-1/3"></div>
|
||||||
<div className="w-3/4 md:w-2/3">
|
<div className="w-3/4 md:w-2/3 relative hover:scale-105 transition-transform duration-300">
|
||||||
<img
|
<Image
|
||||||
src="/images/info/jump.png"
|
src="/images/info/jump.png"
|
||||||
alt="jump"
|
alt="jump"
|
||||||
className="w-full h-auto object-cover hover:scale-105 transition-transform duration-300"
|
width={400}
|
||||||
|
height={300}
|
||||||
|
className="w-full h-auto object-cover"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+26
-20
@@ -1,6 +1,7 @@
|
|||||||
/* eslint-disable @next/next/no-img-element */
|
/* eslint-disable @next/next/no-img-element */
|
||||||
import { fluxgore } from "@/utils/fonts";
|
import { fluxgore } from "@/utils/fonts";
|
||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
function Kamaz() {
|
function Kamaz() {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
@@ -53,16 +54,17 @@ function Kamaz() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className="bg-[#161616] relative md:pt-64 pb-16 md:pb-32">
|
||||||
className="bg-[#161616] relative md:pt-64 pb-16 md:pb-32"
|
{/* Background noise pattern */}
|
||||||
style={{
|
<Image
|
||||||
backgroundImage: `url('/images/noise.svg')`,
|
src="/images/noise.svg"
|
||||||
backgroundSize: "cover",
|
alt=""
|
||||||
backgroundRepeat: "repeat",
|
fill
|
||||||
backgroundBlendMode: "overlay",
|
className="object-cover opacity-50 mix-blend-overlay"
|
||||||
}}
|
quality={75}
|
||||||
>
|
/>
|
||||||
<div className="container mx-auto px-4 max-w-7xl">
|
|
||||||
|
<div className="container mx-auto px-4 max-w-7xl relative z-10">
|
||||||
<div
|
<div
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
className="flex flex-col lg:flex-row gap-8 lg:gap-16 opacity-0 translate-y-8 transition-all duration-700 ease-out"
|
className="flex flex-col lg:flex-row gap-8 lg:gap-16 opacity-0 translate-y-8 transition-all duration-700 ease-out"
|
||||||
@@ -81,16 +83,20 @@ function Kamaz() {
|
|||||||
className="mt-12 md:mt-16 opacity-0 translate-y-8 transition-all duration-700 delay-300 ease-out"
|
className="mt-12 md:mt-16 opacity-0 translate-y-8 transition-all duration-700 delay-300 ease-out"
|
||||||
>
|
>
|
||||||
<div className="relative group">
|
<div className="relative group">
|
||||||
<img
|
<div className="relative w-full max-h-[600px] aspect-[16/9]">
|
||||||
src="/images/kamaz.webp"
|
<Image
|
||||||
alt="Tech Festival - Previous Event Highlights"
|
src="/images/kamaz.webp"
|
||||||
className="w-full h-auto max-h-[600px] object-cover shadow-2xl"
|
alt="Tech Festival - Previous Event Highlights"
|
||||||
style={{
|
fill
|
||||||
clipPath:
|
className="object-cover shadow-2xl"
|
||||||
"polygon(20px 0, 100% 0, 100% calc(100% - 20px), calc(100% - 20px) 100%, 0 100%, 0 20px)",
|
style={{
|
||||||
}}
|
clipPath:
|
||||||
loading="lazy"
|
"polygon(20px 0, 100% 0, 100% calc(100% - 20px), calc(100% - 20px) 100%, 0 100%, 0 20px)",
|
||||||
/>
|
}}
|
||||||
|
loading="lazy"
|
||||||
|
quality={85}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-black/20 to-transparent pointer-events-none rounded-lg" />
|
<div className="absolute inset-0 bg-gradient-to-t from-black/20 to-transparent pointer-events-none rounded-lg" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+78
-112
@@ -1,69 +1,22 @@
|
|||||||
/* eslint-disable @next/next/no-img-element */
|
/* eslint-disable @next/next/no-img-element */
|
||||||
import { fluxgore } from "@/utils/fonts";
|
import { fluxgore } from "@/utils/fonts";
|
||||||
import Button from "./Button";
|
import Button from "./Button";
|
||||||
import { useEffect, useRef } from "react";
|
import Image from "next/image";
|
||||||
|
|
||||||
function Partners() {
|
function Partners() {
|
||||||
const elementsRef = useRef<(HTMLDivElement | null)[]>([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const observer = new IntersectionObserver(
|
|
||||||
(entries) => {
|
|
||||||
entries.forEach((entry) => {
|
|
||||||
if (entry.isIntersecting) {
|
|
||||||
entry.target.classList.add("animate-fade-in-up");
|
|
||||||
entry.target.classList.remove("opacity-0", "translate-y-8");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
{ threshold: 0.1, rootMargin: "0px 0px -50px 0px" }
|
|
||||||
);
|
|
||||||
|
|
||||||
elementsRef.current.forEach((el) => {
|
|
||||||
if (el) observer.observe(el);
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => observer.disconnect();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const addToRefs = (el: HTMLDivElement | null) => {
|
|
||||||
if (el && !elementsRef.current.includes(el)) {
|
|
||||||
elementsRef.current.push(el);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div id="partners" className="bg-[#161616] relative py-16 sm:py-32 lg:py-52">
|
||||||
id="partners"
|
{/* Background noise pattern */}
|
||||||
className="bg-[#161616] relative py-16 sm:py-32 lg:py-52"
|
<Image
|
||||||
style={{
|
src="/images/noise.svg"
|
||||||
backgroundImage: `url('/images/noise.svg')`,
|
alt=""
|
||||||
backgroundSize: "cover",
|
fill
|
||||||
backgroundRepeat: "repeat",
|
className="object-cover opacity-50 mix-blend-overlay"
|
||||||
backgroundBlendMode: "overlay",
|
quality={75}
|
||||||
}}
|
/>
|
||||||
>
|
|
||||||
<style jsx>{`
|
|
||||||
@keyframes fadeInUp {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(30px);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.animate-fade-in-up {
|
|
||||||
animation: fadeInUp 0.6s ease-out forwards;
|
|
||||||
}
|
|
||||||
`}</style>
|
|
||||||
|
|
||||||
<div className="container mx-auto px-4">
|
<div className="container mx-auto px-4 relative z-10">
|
||||||
<div
|
<div>
|
||||||
ref={addToRefs}
|
|
||||||
className="opacity-0 translate-y-8 transition-all duration-700"
|
|
||||||
>
|
|
||||||
<h1
|
<h1
|
||||||
className={`${fluxgore.className} text-4xl sm:text-5xl md:text-6xl lg:text-7xl text-white relative uppercase`}
|
className={`${fluxgore.className} text-4xl sm:text-5xl md:text-6xl lg:text-7xl text-white relative uppercase`}
|
||||||
>
|
>
|
||||||
@@ -71,61 +24,74 @@ function Partners() {
|
|||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-8 sm:gap-12 md:gap-16 lg:gap-24 mt-8 sm:mt-12 lg:mt-16">
|
||||||
ref={addToRefs}
|
<div className="w-auto h-16 sm:h-20 lg:h-24 relative hover:scale-110 transition-transform duration-300">
|
||||||
className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-8 sm:gap-12 md:gap-16 lg:gap-24 mt-8 sm:mt-12 lg:mt-16 opacity-0 translate-y-8 transition-all duration-700 delay-200"
|
<Image
|
||||||
>
|
src="/logos/dep.svg"
|
||||||
<img
|
alt="Dep Logo"
|
||||||
src="/logos/dep.svg"
|
fill
|
||||||
className="w-auto h-16 sm:h-20 lg:h-24 object-contain hover:scale-110 transition-transform duration-300"
|
className="object-contain"
|
||||||
alt="Dep Logo"
|
/>
|
||||||
/>
|
</div>
|
||||||
<img
|
<div className="w-auto h-16 sm:h-20 lg:h-24 relative hover:scale-110 transition-transform duration-300">
|
||||||
src="/logos/mos.svg"
|
<Image
|
||||||
className="w-auto h-16 sm:h-20 lg:h-24 object-contain hover:scale-110 transition-transform duration-300"
|
src="/logos/mos.svg"
|
||||||
alt="Mos Logo"
|
alt="Mos Logo"
|
||||||
/>
|
fill
|
||||||
<img
|
className="object-contain"
|
||||||
src="/logos/raf.png"
|
/>
|
||||||
className="w-auto h-16 sm:h-20 lg:h-24 object-contain hover:scale-110 transition-transform duration-300"
|
</div>
|
||||||
alt="Raf Logo"
|
<div className="w-auto h-16 sm:h-20 lg:h-24 relative hover:scale-110 transition-transform duration-300">
|
||||||
/>
|
<Image
|
||||||
<img
|
src="/logos/raf.png"
|
||||||
src="/logos/ctvs.png"
|
alt="Raf Logo"
|
||||||
className="w-auto h-16 sm:h-20 lg:h-24 object-contain hover:scale-110 transition-transform duration-300"
|
fill
|
||||||
alt="Ctvs Logo"
|
className="object-contain"
|
||||||
/>
|
/>
|
||||||
<img
|
</div>
|
||||||
src="/logos/xenum.svg"
|
<div className="w-auto h-16 sm:h-20 lg:h-24 relative hover:scale-110 transition-transform duration-300">
|
||||||
className="w-auto h-16 sm:h-20 lg:h-24 object-contain hover:scale-110 transition-transform duration-300"
|
<Image
|
||||||
alt="Xenum Logo"
|
src="/logos/ctvs.png"
|
||||||
/>
|
alt="Ctvs Logo"
|
||||||
<img
|
fill
|
||||||
src="/logos/GNVOil.svg"
|
className="object-contain"
|
||||||
className="w-auto h-16 sm:h-20 lg:h-24 object-contain hover:scale-110 transition-transform duration-300"
|
/>
|
||||||
alt="GNVOil Logo"
|
</div>
|
||||||
/>
|
<div className="w-auto h-16 sm:h-20 lg:h-24 relative hover:scale-110 transition-transform duration-300">
|
||||||
<img
|
<Image
|
||||||
src="/logos/Q8oils.svg"
|
src="/logos/xenum.svg"
|
||||||
className="w-auto h-16 sm:h-20 lg:h-24 object-contain hover:scale-110 transition-transform duration-300"
|
alt="Xenum Logo"
|
||||||
alt="Q8oils Logo"
|
fill
|
||||||
/>
|
className="object-contain"
|
||||||
<img
|
/>
|
||||||
src="/logos/IMG_3601.png"
|
</div>
|
||||||
className="w-auto h-16 sm:h-20 lg:h-24 object-contain hover:scale-110 transition-transform duration-300"
|
<div className="w-auto h-16 sm:h-20 lg:h-24 relative hover:scale-110 transition-transform duration-300">
|
||||||
alt="Q8oils Logo"
|
<Image
|
||||||
/>
|
src="/logos/GNVOil.svg"
|
||||||
{/* <img
|
alt="GNVOil Logo"
|
||||||
src="/logos/smp.png"
|
fill
|
||||||
className="w-auto h-16 sm:h-20 lg:h-24 object-contain hover:scale-110 transition-transform duration-300"
|
className="object-contain"
|
||||||
alt="SMP Logo"
|
/>
|
||||||
/> */}
|
</div>
|
||||||
|
<div className="w-auto h-16 sm:h-20 lg:h-24 relative hover:scale-110 transition-transform duration-300">
|
||||||
|
<Image
|
||||||
|
src="/logos/Q8oils.svg"
|
||||||
|
alt="Q8oils Logo"
|
||||||
|
fill
|
||||||
|
className="object-contain"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="w-auto h-16 sm:h-20 lg:h-24 relative hover:scale-110 transition-transform duration-300">
|
||||||
|
<Image
|
||||||
|
src="/logos/IMG_3601.png"
|
||||||
|
alt="Partner Logo"
|
||||||
|
fill
|
||||||
|
className="object-contain"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div>
|
||||||
ref={addToRefs}
|
|
||||||
className="opacity-0 translate-y-8 transition-all duration-700 delay-500"
|
|
||||||
>
|
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const mail = "mailto:ftvs.partners@yandex.ru";
|
const mail = "mailto:ftvs.partners@yandex.ru";
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/* eslint-disable @next/next/no-img-element */
|
/* eslint-disable @next/next/no-img-element */
|
||||||
import { fluxgore, gothampro } from "@/utils/fonts";
|
import { fluxgore, gothampro } from "@/utils/fonts";
|
||||||
import Button from "./Button";
|
import Button from "./Button";
|
||||||
|
import Image from "next/image";
|
||||||
import { ReactNode, useState, useMemo } from "react";
|
import { ReactNode, useState, useMemo } from "react";
|
||||||
|
|
||||||
interface ScheduleData {
|
interface ScheduleData {
|
||||||
@@ -125,11 +126,16 @@ function Scheme({ scheduleData = [] }: SchemeProps) {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<img
|
<div className="mt-10 md:mt-20 w-full relative">
|
||||||
src="/images/scheme/map.png"
|
<Image
|
||||||
alt="Festival Map"
|
src="/images/scheme/map.png"
|
||||||
className="mt-10 md:mt-20 w-full h-auto"
|
alt="Festival Map"
|
||||||
/>
|
width={1200}
|
||||||
|
height={800}
|
||||||
|
className="w-full h-auto"
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Date Selection */}
|
{/* Date Selection */}
|
||||||
<div className="flex flex-col md:flex-row mt-10 md:mt-40 space-y-3 md:space-y-0 md:space-x-5 items-center justify-center">
|
<div className="flex flex-col md:flex-row mt-10 md:mt-40 space-y-3 md:space-y-0 md:space-x-5 items-center justify-center">
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
/* eslint-disable @next/next/no-img-element */
|
/* eslint-disable @next/next/no-img-element */
|
||||||
import { fluxgore, gothampro } from "@/utils/fonts";
|
import { fluxgore, gothampro } from "@/utils/fonts";
|
||||||
import { useEffect, useRef } from "react";
|
|
||||||
|
|
||||||
interface VideoStatsProps {
|
interface VideoStatsProps {
|
||||||
number: string;
|
number: string;
|
||||||
@@ -27,34 +26,6 @@ function VideoStats(props: VideoStatsProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Video() {
|
function Video() {
|
||||||
const elementsRef = useRef<(HTMLDivElement | null)[]>([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const observer = new IntersectionObserver(
|
|
||||||
(entries) => {
|
|
||||||
entries.forEach((entry) => {
|
|
||||||
if (entry.isIntersecting) {
|
|
||||||
entry.target.classList.add("animate-fade-in-up");
|
|
||||||
entry.target.classList.remove("opacity-0", "translate-y-8");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
{ threshold: 0.1, rootMargin: "0px 0px -50px 0px" }
|
|
||||||
);
|
|
||||||
|
|
||||||
elementsRef.current.forEach((el) => {
|
|
||||||
if (el) observer.observe(el);
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => observer.disconnect();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const addToRefs = (el: HTMLDivElement | null) => {
|
|
||||||
if (el && !elementsRef.current.includes(el)) {
|
|
||||||
elementsRef.current.push(el);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="bg-[#161616] relative overflow-hidden pt-10 md:pt-20"
|
className="bg-[#161616] relative overflow-hidden pt-10 md:pt-20"
|
||||||
@@ -65,22 +36,6 @@ function Video() {
|
|||||||
backgroundBlendMode: "overlay",
|
backgroundBlendMode: "overlay",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<style jsx>{`
|
|
||||||
@keyframes fadeInUp {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(30px);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.animate-fade-in-up {
|
|
||||||
animation: fadeInUp 0.6s ease-out forwards;
|
|
||||||
}
|
|
||||||
`}</style>
|
|
||||||
|
|
||||||
<img
|
<img
|
||||||
className="absolute top-0 right-0 object-cover"
|
className="absolute top-0 right-0 object-cover"
|
||||||
src="/images/video/arrows.svg"
|
src="/images/video/arrows.svg"
|
||||||
@@ -88,10 +43,7 @@ function Video() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="container mx-auto px-4">
|
<div className="container mx-auto px-4">
|
||||||
<div
|
<div className="flex flex-col md:flex-row space-y-6 md:space-y-0 md:space-x-16">
|
||||||
ref={addToRefs}
|
|
||||||
className="flex flex-col md:flex-row space-y-6 md:space-y-0 md:space-x-16 opacity-0 translate-y-8 transition-all duration-700"
|
|
||||||
>
|
|
||||||
<h1
|
<h1
|
||||||
className={`${fluxgore.className} text-4xl md:text-7xl text-white relative uppercase`}
|
className={`${fluxgore.className} text-4xl md:text-7xl text-white relative uppercase`}
|
||||||
>
|
>
|
||||||
@@ -107,10 +59,7 @@ function Video() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div className="flex mt-8 md:mt-14">
|
||||||
ref={addToRefs}
|
|
||||||
className="flex mt-8 md:mt-14 opacity-0 translate-y-8 transition-all duration-700 delay-200"
|
|
||||||
>
|
|
||||||
<iframe
|
<iframe
|
||||||
src="https://vkvideo.ru/video_ext.php?oid=-23293707&id=456242039&hd=2"
|
src="https://vkvideo.ru/video_ext.php?oid=-23293707&id=456242039&hd=2"
|
||||||
frameBorder="0"
|
frameBorder="0"
|
||||||
@@ -125,10 +74,7 @@ function Video() {
|
|||||||
></iframe>
|
></iframe>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-8 md:gap-24 mt-16 md:mt-36 pb-32 md:pb-64">
|
||||||
ref={addToRefs}
|
|
||||||
className="grid grid-cols-2 md:grid-cols-4 gap-8 md:gap-24 mt-16 md:mt-36 pb-32 md:pb-64 opacity-0 translate-y-8 transition-all duration-700 delay-500"
|
|
||||||
>
|
|
||||||
<div className="hover:scale-105 transition-transform duration-300">
|
<div className="hover:scale-105 transition-transform duration-300">
|
||||||
<VideoStats number="260" label="[ единиц техники ]" />
|
<VideoStats number="260" label="[ единиц техники ]" />
|
||||||
</div>
|
</div>
|
||||||
@@ -149,12 +95,6 @@ function Video() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<img
|
|
||||||
className="absolute bottom-0 object-cover w-full"
|
|
||||||
src="/images/video/paper_tear.png"
|
|
||||||
alt="Paper tear"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,320 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import PocketBase from "pocketbase";
|
||||||
|
import { fluxgore, gothampro } from "@/utils/fonts";
|
||||||
|
|
||||||
|
const pb = new PocketBase("https://base.mossport.info");
|
||||||
|
|
||||||
|
interface CSVExporterProps {
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CSVExporter: React.FC<CSVExporterProps> = ({ className = '' }) => {
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [selectedCollection, setSelectedCollection] = useState('forms');
|
||||||
|
const [selectedType, setSelectedType] = useState('');
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
||||||
|
const [credentials, setCredentials] = useState({ email: "", password: "" });
|
||||||
|
const [authError, setAuthError] = useState("");
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
const exportTypes = [
|
||||||
|
{ value: '', label: 'Все типы' },
|
||||||
|
{ value: 'exhibition', label: 'Выставка' },
|
||||||
|
{ value: 'fight', label: 'Дрифт-битва' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const collections = [
|
||||||
|
{ value: 'forms', label: 'Формы' },
|
||||||
|
// Add other collections if needed
|
||||||
|
];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Check if user is already authenticated
|
||||||
|
if (pb.authStore.isValid) {
|
||||||
|
setIsAuthenticated(true);
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleLogin = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setAuthError("");
|
||||||
|
|
||||||
|
try {
|
||||||
|
await pb.admins.authWithPassword(credentials.email, credentials.password);
|
||||||
|
setIsAuthenticated(true);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Auth error:", error);
|
||||||
|
setAuthError("Неверный email или пароль");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLogout = () => {
|
||||||
|
pb.authStore.clear();
|
||||||
|
setIsAuthenticated(false);
|
||||||
|
setCredentials({ email: "", password: "" });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleExport = async () => {
|
||||||
|
try {
|
||||||
|
setIsLoading(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
// Build query parameters
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
collection: selectedCollection,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (selectedType) {
|
||||||
|
params.append('type', selectedType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add auth token if available
|
||||||
|
if (pb.authStore.token) {
|
||||||
|
params.append('token', pb.authStore.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the request
|
||||||
|
const response = await fetch(`/api/csv?${params.toString()}`);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorData = await response.json();
|
||||||
|
throw new Error(errorData.message || 'Ошибка при экспорте данных');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the filename from response headers
|
||||||
|
const contentDisposition = response.headers.get('Content-Disposition');
|
||||||
|
let filename = 'export.csv';
|
||||||
|
|
||||||
|
if (contentDisposition) {
|
||||||
|
const filenameMatch = contentDisposition.match(/filename="(.+)"/);
|
||||||
|
if (filenameMatch) {
|
||||||
|
filename = filenameMatch[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create blob and download
|
||||||
|
const blob = await response.blob();
|
||||||
|
const url = window.URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = filename;
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
setError(err instanceof Error ? err.message : 'Произошла ошибка');
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Loading state
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-center min-h-screen bg-gray-50">
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="w-12 h-12 border-4 border-blue-600 border-t-transparent rounded-full animate-spin mx-auto mb-4"></div>
|
||||||
|
<div className={`${gothampro.className} text-xl text-gray-600`}>
|
||||||
|
Загрузка...
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authentication form
|
||||||
|
if (!isAuthenticated) {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-gray-50 to-gray-100">
|
||||||
|
<div className="max-w-md w-full mx-4">
|
||||||
|
<div className="bg-white rounded-xl shadow-xl p-8 space-y-8">
|
||||||
|
<div className="text-center">
|
||||||
|
<h2 className={`${fluxgore.className} text-3xl text-gray-900 mb-2`}>
|
||||||
|
Экспорт данных CSV
|
||||||
|
</h2>
|
||||||
|
<p className={`${gothampro.className} text-gray-600`}>
|
||||||
|
Войдите для доступа к экспорту данных
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<form className="space-y-6" onSubmit={handleLogin}>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
htmlFor="email"
|
||||||
|
className={`${gothampro.className} block text-sm font-medium text-gray-700 mb-2`}
|
||||||
|
>
|
||||||
|
Email администратора
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="email"
|
||||||
|
name="email"
|
||||||
|
type="email"
|
||||||
|
required
|
||||||
|
className={`${gothampro.className} w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200`}
|
||||||
|
placeholder="admin@example.com"
|
||||||
|
value={credentials.email}
|
||||||
|
onChange={(e) =>
|
||||||
|
setCredentials((prev) => ({
|
||||||
|
...prev,
|
||||||
|
email: e.target.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
htmlFor="password"
|
||||||
|
className={`${gothampro.className} block text-sm font-medium text-gray-700 mb-2`}
|
||||||
|
>
|
||||||
|
Пароль
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="password"
|
||||||
|
name="password"
|
||||||
|
type="password"
|
||||||
|
required
|
||||||
|
className={`${gothampro.className} w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200`}
|
||||||
|
placeholder="••••••••"
|
||||||
|
value={credentials.password}
|
||||||
|
onChange={(e) =>
|
||||||
|
setCredentials((prev) => ({
|
||||||
|
...prev,
|
||||||
|
password: e.target.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{authError && (
|
||||||
|
<div className={`${gothampro.className} text-red-600 text-sm text-center bg-red-50 p-3 rounded-lg`}>
|
||||||
|
{authError}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className={`${fluxgore.className} w-full py-3 px-4 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2`}
|
||||||
|
>
|
||||||
|
Войти
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main CSV exporter interface
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50">
|
||||||
|
{/* Header */}
|
||||||
|
<div className="bg-white shadow-sm border-b">
|
||||||
|
<div className="max-w-7xl mx-auto px-6 py-6">
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<h1 className={`${fluxgore.className} text-2xl md:text-4xl text-[#060606] uppercase`}>
|
||||||
|
Экспорт данных в CSV
|
||||||
|
</h1>
|
||||||
|
<button
|
||||||
|
onClick={handleLogout}
|
||||||
|
className={`${fluxgore.className} bg-gray-600 hover:bg-gray-700 text-white px-6 py-3 text-sm font-medium uppercase tracking-wide transition-colors rounded-lg`}
|
||||||
|
>
|
||||||
|
Выйти
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Content */}
|
||||||
|
<div className="max-w-2xl mx-auto px-6 py-8">
|
||||||
|
<div className={`csv-exporter ${className} bg-white border border-gray-200 rounded-xl shadow-sm p-8`}>
|
||||||
|
<div className="csv-exporter__content space-y-6">
|
||||||
|
<h3 className={`${fluxgore.className} text-xl text-[#1068B0] border-b border-gray-200 pb-2`}>
|
||||||
|
Настройки экспорта
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<div className="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg flex items-center gap-3">
|
||||||
|
<span className="text-lg">⚠️</span>
|
||||||
|
<span className={gothampro.className}>{error}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label htmlFor="collection" className={`${gothampro.className} block text-sm font-medium text-gray-700`}>
|
||||||
|
Коллекция:
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
id="collection"
|
||||||
|
value={selectedCollection}
|
||||||
|
onChange={(e) => setSelectedCollection(e.target.value)}
|
||||||
|
className={`${gothampro.className} w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 bg-white`}
|
||||||
|
disabled={isLoading}
|
||||||
|
>
|
||||||
|
{collections.map((collection) => (
|
||||||
|
<option key={collection.value} value={collection.value}>
|
||||||
|
{collection.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label htmlFor="type" className={`${gothampro.className} block text-sm font-medium text-gray-700`}>
|
||||||
|
Тип данных:
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
id="type"
|
||||||
|
value={selectedType}
|
||||||
|
onChange={(e) => setSelectedType(e.target.value)}
|
||||||
|
className={`${gothampro.className} w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 bg-white`}
|
||||||
|
disabled={isLoading}
|
||||||
|
>
|
||||||
|
{exportTypes.map((type) => (
|
||||||
|
<option key={type.value} value={type.value}>
|
||||||
|
{type.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={handleExport}
|
||||||
|
disabled={isLoading}
|
||||||
|
className={`${fluxgore.className} w-full bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white px-6 py-4 rounded-lg font-medium uppercase tracking-wide transition-colors duration-200 flex items-center justify-center gap-3`}
|
||||||
|
>
|
||||||
|
{isLoading ? (
|
||||||
|
<>
|
||||||
|
<div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin"></div>
|
||||||
|
Экспорт...
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<span className="text-lg">📥</span>
|
||||||
|
Экспортировать CSV
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={`${gothampro.className} text-sm text-gray-500 bg-gray-50 p-4 rounded-lg`}>
|
||||||
|
<h4 className="font-medium text-gray-700 mb-2">Информация:</h4>
|
||||||
|
<ul className="space-y-1 text-xs">
|
||||||
|
<li>• Экспорт включает все поля в зависимости от выбранного типа</li>
|
||||||
|
<li>• Файл сохраняется в формате CSV с поддержкой UTF-8</li>
|
||||||
|
<li>• Имя файла содержит коллекцию, тип и дату экспорта</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CSVExporter;
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
function PilotsPage() {
|
||||||
|
return (
|
||||||
|
<div className="container mx-auto px-4 py-8">
|
||||||
|
<h1 className="text-3xl font-bold mb-6">Пилоты Битвы за Москву</h1>
|
||||||
|
|
||||||
|
<p className="text-lg mb-8">Список участников вот-вот станет доступен</p>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
href="/"
|
||||||
|
className="text-blue-600 hover:text-blue-800 underline"
|
||||||
|
>
|
||||||
|
Вернуться на главную
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PilotsPage
|
||||||
@@ -32,8 +32,10 @@ function FightFormPage() {
|
|||||||
});
|
});
|
||||||
const [carPhotos, setCarPhotos] = useState<File[]>([]);
|
const [carPhotos, setCarPhotos] = useState<File[]>([]);
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
// Add a key to force re-render of Fileupload component
|
|
||||||
const [fileUploadKey, setFileUploadKey] = useState(0);
|
const [fileUploadKey, setFileUploadKey] = useState(0);
|
||||||
|
|
||||||
|
// Add registration disabled state
|
||||||
|
const isRegistrationDisabled = true;
|
||||||
|
|
||||||
const { value: phoneValue, handleChange: handlePhoneChange } = usePhoneMask();
|
const { value: phoneValue, handleChange: handlePhoneChange } = usePhoneMask();
|
||||||
|
|
||||||
@@ -47,6 +49,11 @@ function FightFormPage() {
|
|||||||
const handleSubmit = async (e: React.FormEvent) => {
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (isRegistrationDisabled) {
|
||||||
|
alert("Регистрация временно закрыта");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!checkboxValues.includes("terms")) {
|
if (!checkboxValues.includes("terms")) {
|
||||||
alert("Необходимо согласие на обработку персональных данных");
|
alert("Необходимо согласие на обработку персональных данных");
|
||||||
return;
|
return;
|
||||||
@@ -126,7 +133,15 @@ function FightFormPage() {
|
|||||||
Регистрация на Битву за Москву
|
Регистрация на Битву за Москву
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-6 max-w-2xl w-full">
|
{isRegistrationDisabled && (
|
||||||
|
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-6 max-w-2xl w-full">
|
||||||
|
<p className={`${gothampro.className} text-center`}>
|
||||||
|
Регистрация закрыта
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<form onSubmit={handleSubmit} className={`space-y-6 max-w-2xl w-full ${isRegistrationDisabled ? 'opacity-50 pointer-events-none' : ''}`}>
|
||||||
<Input
|
<Input
|
||||||
label="Фамилия"
|
label="Фамилия"
|
||||||
placeholder="Введите вашу фамилию"
|
placeholder="Введите вашу фамилию"
|
||||||
@@ -275,10 +290,10 @@ function FightFormPage() {
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting || isRegistrationDisabled}
|
||||||
className={`${fluxgore.className} bg-[#1068B0] hover:bg-[#0d5a96] text-white px-9 py-4 text-base font-medium uppercase tracking-wide disabled:opacity-50 w-full`}
|
className={`${fluxgore.className} bg-[#1068B0] hover:bg-[#0d5a96] text-white px-9 py-4 text-base font-medium uppercase tracking-wide disabled:opacity-50 w-full`}
|
||||||
>
|
>
|
||||||
{isSubmitting ? "Отправка..." : "Отправить"}
|
{isRegistrationDisabled ? "Регистрация закрыта" : isSubmitting ? "Отправка..." : "Отправить"}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+279
-69
@@ -18,23 +18,16 @@ export default function Home() {
|
|||||||
{
|
{
|
||||||
date: "5 сентября",
|
date: "5 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "10:30",
|
start: "11:40",
|
||||||
stop: "11:30",
|
stop: "16:00",
|
||||||
activity: "Брифинг пилотов",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
date: "5 сентября",
|
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
|
||||||
start: "11:30",
|
|
||||||
stop: "16:30",
|
|
||||||
activity: "Тренировка ДЖИМХАНА",
|
activity: "Тренировка ДЖИМХАНА",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "5 сентября",
|
date: "5 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "16:30",
|
start: "16:15",
|
||||||
stop: "20:30",
|
stop: "20:30",
|
||||||
activity: "Тренировка ДЖИМХАНА",
|
activity: "Квалификация ДЖИМХАНА",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "5 сентября",
|
date: "5 сентября",
|
||||||
@@ -53,14 +46,21 @@ export default function Home() {
|
|||||||
{
|
{
|
||||||
date: "5 сентября",
|
date: "5 сентября",
|
||||||
location: "КАРТИНГ",
|
location: "КАРТИНГ",
|
||||||
start: "12:00",
|
start: "11:00",
|
||||||
stop: "16:30",
|
stop: "15:00",
|
||||||
activity: "Картинг без границ",
|
activity: "Картинг без границ",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "5 сентября",
|
date: "5 сентября",
|
||||||
location: "КАРТИНГ",
|
location: "КАРТИНГ",
|
||||||
start: "18:00",
|
start: "15:00",
|
||||||
|
stop: "19:00",
|
||||||
|
activity: "Заезды участников СВО",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "5 сентября",
|
||||||
|
location: "КАРТИНГ",
|
||||||
|
start: "19:00",
|
||||||
stop: "21:30",
|
stop: "21:30",
|
||||||
activity: "Тренировки гонки 12 часов",
|
activity: "Тренировки гонки 12 часов",
|
||||||
},
|
},
|
||||||
@@ -79,115 +79,143 @@ export default function Home() {
|
|||||||
activity: "Регистрация участников",
|
activity: "Регистрация участников",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "6 сентября",
|
date: "5 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ЭКШН-СПОРТ",
|
||||||
start: "9:30",
|
start: "15:00",
|
||||||
stop: "10:15",
|
stop: "19:00",
|
||||||
activity: "Брифинг",
|
activity: "Проба площадки",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "5 сентября",
|
||||||
|
location: "ДЕТСКАЯ ПЛОЩАДКА",
|
||||||
|
start: "10:00",
|
||||||
|
stop: "20:00",
|
||||||
|
activity: "Свободный день",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "6 сентября",
|
date: "6 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "10:15",
|
start: "10:30",
|
||||||
stop: "11:15",
|
stop: "11:00",
|
||||||
activity: "Тренировка ДЖИМХАНА",
|
activity: "Тренировка ДЖИМХАНА",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "6 сентября",
|
date: "6 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "11:15",
|
start: "11:00",
|
||||||
stop: "12:00",
|
stop: "12:15",
|
||||||
activity: "G-Такси",
|
activity: "G-Такси",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "6 сентября",
|
date: "6 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "12:00",
|
start: "12:15",
|
||||||
stop: "12:30",
|
stop: "12:30",
|
||||||
activity: "Выступление стант-райдеров",
|
activity: "КАМАЗ такси",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "6 сентября",
|
date: "6 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "12:30",
|
start: "12:30",
|
||||||
stop: "13:30",
|
stop: "13:00",
|
||||||
|
activity: "Стант райдинг",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "6 сентября",
|
||||||
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
|
start: "13:00",
|
||||||
|
stop: "13:50",
|
||||||
activity: "Парад пилотов",
|
activity: "Парад пилотов",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "6 сентября",
|
date: "6 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "13:30",
|
start: "14:00",
|
||||||
stop: "15:30",
|
stop: "16:00",
|
||||||
activity: "ДЖИМХАНА Топ-32",
|
activity: "ДЖИМХАНА Топ-32",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "6 сентября",
|
date: "6 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "15:30",
|
start: "16:00",
|
||||||
stop: "16:30",
|
stop: "16:45",
|
||||||
activity: "Выступление КАМАЗ-МАСТЕР и G-такси",
|
activity: "G-такси",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "6 сентября",
|
date: "6 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "16:30",
|
start: "16:45",
|
||||||
stop: "17:30",
|
stop: "17:00",
|
||||||
|
activity: "КАМАЗ такси",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "6 сентября",
|
||||||
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
|
start: "17:00",
|
||||||
|
stop: "18:00",
|
||||||
activity: "ДЖИМХАНА Топ-16",
|
activity: "ДЖИМХАНА Топ-16",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "6 сентября",
|
date: "6 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "17:30",
|
start: "18:00",
|
||||||
stop: "18:30",
|
stop: "18:30",
|
||||||
activity: "Выступление КАМАЗ-МАСТЕР и G-такси",
|
activity: "КАМАЗ-МАСТЕР и Джиган",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "6 сентября",
|
date: "6 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "18:30",
|
start: "19:00",
|
||||||
stop: "18:50",
|
stop: "19:20",
|
||||||
activity: "Медиа-заезд",
|
activity: "Медиа-заезд",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "6 сентября",
|
date: "6 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "18:50",
|
start: "19:20",
|
||||||
stop: "19:20",
|
stop: "19:40",
|
||||||
activity: "ДЖИМХАНА Топ-8 и ТОП-4",
|
activity: "ДЖИМХАНА Топ-8 и ТОП-4",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
date: "6 сентября",
|
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
|
||||||
start: "19:20",
|
|
||||||
stop: "19:35",
|
|
||||||
activity: "ДЖИМХАНА заезд за 3-е место",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
date: "6 сентября",
|
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
|
||||||
start: "19:35",
|
|
||||||
stop: "19:40",
|
|
||||||
activity: "ДЖИМХАНА парад ФИНАЛИСТОВ",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
date: "6 сентября",
|
date: "6 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "19:40",
|
start: "19:40",
|
||||||
stop: "19:50",
|
stop: "19:55",
|
||||||
|
activity: "G-такси",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "6 сентября",
|
||||||
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
|
start: "19:55",
|
||||||
|
stop: "20:10",
|
||||||
|
activity: "КАМАЗ такси",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "6 сентября",
|
||||||
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
|
start: "20:10",
|
||||||
|
stop: "20:30",
|
||||||
|
activity: "ДЖИМХАНА Топ-4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "6 сентября",
|
||||||
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
|
start: "20:30",
|
||||||
|
stop: "20:40",
|
||||||
activity: "ДЖИМХАНА Финал",
|
activity: "ДЖИМХАНА Финал",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "6 сентября",
|
date: "6 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "19:50",
|
start: "20:40",
|
||||||
stop: "20:00",
|
stop: "21:00",
|
||||||
activity: "СуперФинал с Цареградцевым",
|
activity: "СуперФинал с Цареградцевым",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "6 сентября",
|
date: "6 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "20:00",
|
start: "21:00",
|
||||||
stop: "20:30",
|
stop: "21:15",
|
||||||
activity: "Награждение",
|
activity: "Награждение",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -242,9 +270,86 @@ export default function Home() {
|
|||||||
{
|
{
|
||||||
date: "6 сентября",
|
date: "6 сентября",
|
||||||
location: "МОТОТРЕК",
|
location: "МОТОТРЕК",
|
||||||
start: "10:00",
|
start: "10:30",
|
||||||
stop: "20:00",
|
stop: "11:55",
|
||||||
activity: "Выездной мотокросс-лагерь",
|
activity: "Разминка 65-85",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "6 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "11:00",
|
||||||
|
stop: "11:25",
|
||||||
|
activity: "Разминка 125-450",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "6 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "11:30",
|
||||||
|
stop: "12:10",
|
||||||
|
activity: "Мастер Класс Бобрышева 65-85 (1 сессия)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "6 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "12:20",
|
||||||
|
stop: "13:00",
|
||||||
|
activity: "Мастек Класс Бобрышева 125-450 (1 сессия)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "6 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "13:00",
|
||||||
|
stop: "15:00",
|
||||||
|
activity: "Автограф-сессия",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "6 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "14:00",
|
||||||
|
stop: "14:40",
|
||||||
|
activity: "Мастер Класс Бобрышева 65-85 (2 сессия)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "6 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "14:50",
|
||||||
|
stop: "15:30",
|
||||||
|
activity: "Мастер Класс Бобрышева 125-450 (2 сессия)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "6 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "15:30",
|
||||||
|
stop: "16:15",
|
||||||
|
activity: "Регистрация на Открытую тренировку",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "6 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "16:30",
|
||||||
|
stop: "17:10",
|
||||||
|
activity: "Класс 65-85",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "6 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "17:10",
|
||||||
|
stop: "17:50",
|
||||||
|
activity: "Открытый",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "6 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "17:50",
|
||||||
|
stop: "18:30",
|
||||||
|
activity: "Класс 65-85",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "6 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "18:30",
|
||||||
|
stop: "19:10",
|
||||||
|
activity: "Открытый",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "6 сентября",
|
date: "6 сентября",
|
||||||
@@ -278,9 +383,16 @@ export default function Home() {
|
|||||||
date: "7 сентября",
|
date: "7 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "12:00",
|
start: "12:00",
|
||||||
stop: "12:30",
|
stop: "12:15",
|
||||||
activity: "Выступление КАМАЗ-МАСТЕР",
|
activity: "Выступление КАМАЗ-МАСТЕР",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
date: "7 сентября",
|
||||||
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
|
start: "12:15",
|
||||||
|
stop: "12:30",
|
||||||
|
activity: "Стант райдинг",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
date: "7 сентября",
|
date: "7 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
@@ -292,9 +404,16 @@ export default function Home() {
|
|||||||
date: "7 сентября",
|
date: "7 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "15:00",
|
start: "15:00",
|
||||||
stop: "15:30",
|
stop: "15:15",
|
||||||
activity: "Выступление КАМАЗ-МАСТЕР",
|
activity: "Выступление КАМАЗ-МАСТЕР",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
date: "7 сентября",
|
||||||
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
|
start: "15:15",
|
||||||
|
stop: "15:30",
|
||||||
|
activity: "Стант райдинг",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
date: "7 сентября",
|
date: "7 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
@@ -306,8 +425,15 @@ export default function Home() {
|
|||||||
date: "7 сентября",
|
date: "7 сентября",
|
||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "18:00",
|
start: "18:00",
|
||||||
|
stop: "18:15",
|
||||||
|
activity: "Выступление КАМАЗ-МАСТЕР",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "7 сентября",
|
||||||
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
|
start: "18:15",
|
||||||
stop: "18:30",
|
stop: "18:30",
|
||||||
activity: "Выступление КАМАЗ-Мастер",
|
activity: "Стант райдинг",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "7 сентября",
|
date: "7 сентября",
|
||||||
@@ -335,7 +461,7 @@ export default function Home() {
|
|||||||
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
location: "ГЛАВНАЯ ПЛОЩАДКА",
|
||||||
start: "20:30",
|
start: "20:30",
|
||||||
stop: "21:00",
|
stop: "21:00",
|
||||||
activity: "Шоу-программа",
|
activity: "Закрытие фестиваля. Выступление Камаз + дрифтеры + мотофристайл + стандрайдинг",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: "7 сентября",
|
date: "7 сентября",
|
||||||
@@ -365,6 +491,90 @@ export default function Home() {
|
|||||||
stop: "20:00",
|
stop: "20:00",
|
||||||
activity: "Выездной мотокросс-лагерь",
|
activity: "Выездной мотокросс-лагерь",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
date: "7 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "10:30",
|
||||||
|
stop: "11:55",
|
||||||
|
activity: "Разминка 65-85",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "7 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "11:00",
|
||||||
|
stop: "11:25",
|
||||||
|
activity: "Разминка 125-450",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "7 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "11:30",
|
||||||
|
stop: "12:10",
|
||||||
|
activity: "Мастер Класс Бобрышева 65-85 (1 сессия)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "7 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "12:20",
|
||||||
|
stop: "13:00",
|
||||||
|
activity: "Мастек Класс Бобрышева 125-450 (1 сессия)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "7 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "13:00",
|
||||||
|
stop: "15:00",
|
||||||
|
activity: "Автограф-сессия",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "7 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "14:00",
|
||||||
|
stop: "14:40",
|
||||||
|
activity: "Мастер Класс Бобрышева 65-85 (2 сессия)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "7 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "14:50",
|
||||||
|
stop: "15:30",
|
||||||
|
activity: "Мастер Класс Бобрышева 125-450 (2 сессия)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "7 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "15:30",
|
||||||
|
stop: "16:15",
|
||||||
|
activity: "Регистрация на Открытую тренировку",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "7 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "16:30",
|
||||||
|
stop: "17:10",
|
||||||
|
activity: "Класс 65-85",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "7 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "17:10",
|
||||||
|
stop: "17:50",
|
||||||
|
activity: "Открытый",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "7 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "17:50",
|
||||||
|
stop: "18:30",
|
||||||
|
activity: "Класс 65-85",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "7 сентября",
|
||||||
|
location: "МОТОТРЕК",
|
||||||
|
start: "18:30",
|
||||||
|
stop: "19:10",
|
||||||
|
activity: "Открытый",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
date: "7 сентября",
|
date: "7 сентября",
|
||||||
location: "ЭКШН-СПОРТ",
|
location: "ЭКШН-СПОРТ",
|
||||||
@@ -398,10 +608,10 @@ export default function Home() {
|
|||||||
<Cover />
|
<Cover />
|
||||||
<Info />
|
<Info />
|
||||||
<Video />
|
<Video />
|
||||||
<Scheme scheduleData={csvData} />
|
{/* <Scheme scheduleData={csvData} /> */}
|
||||||
<Events />
|
{/* <Events /> */}
|
||||||
<Kamaz />
|
{/* <Kamaz /> */}
|
||||||
<Activities />
|
{/* <Activities /> */}
|
||||||
<Partners />
|
<Partners />
|
||||||
<Map />
|
<Map />
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
Reference in New Issue
Block a user