fixes/updates

This commit is contained in:
2024-09-23 10:29:39 +05:00
parent 10aa52ffa2
commit 2d6d595b6a
11 changed files with 155 additions and 225 deletions
+2 -1
View File
@@ -189,8 +189,9 @@ export function ModalWithForm() {
id="description"
placeholder="Опишите вашу задачу"
value={description}
rows={1}
onChange={e => setDescription(e.target.value)}
className="bg-transparent border-b py-4 focus:border-white max-h-[300px] h-auto rounded-none border-[#3D425C] resize-none outline-none transition-all w-full placeholder:h4 placeholder:font-medium placeholder:select-none"
className="bg-transparent border-b py-4 focus:border-white max-h-[300px] h-auto rounded-none border-[#3D425C] resize-none outline-none transition-all w-full placeholder:h4 placeholder:font-medium placeholder:select-none placeholder-shown:overflow-hidden"
/>
</div>
</div>
@@ -1,54 +1,55 @@
import { forwardRef, useRef } from 'react';
import { useRef } from 'react';
import { getIcon } from '../../../../utils/getIcon';
import { useInView } from 'framer-motion';
export const ForTeachingTab = forwardRef<HTMLDivElement>((_, ref) => (
<div
itemProp="forEducation"
itemScope
itemType="https://schema.org/TrainingsForEducation"
ref={ref}
className="overflow-hidden lg:ml-[129px] lg:h-[70vh] sm:h-[80vh] lg:min-w-[calc(100vw-129px)] h-[100vh] min-w-[100vw] sm:sticky lg:top-[30vh] sm:top-[20vh] top-0 lg:px-10 lg:pt-10 sm:px-6 sm:pt-6 px-4 pt-4 lg:border-l bg-[#14161F] border-t border-[#3D425C]"
>
<div className="flex justify-between">
<h2 className="font-medium h2">
Интерактивные тренажеры для учебных заведений
</h2>
<p className="h3 font-medium text-[#3D425C]">03</p>
</div>
<div className="flex justify-between max-sm:flex-col">
<div className="sm:max-w-[calc(500/768*100vw)] mt-6">
<div itemProp="creating" className="space-y-4 lg:max-w-[40vw] flex-1">
<ForTeachingOption
title="cоздание обучающих VR систем"
description="Проведение виртуальных практических работ, создание учебных мастерских и стендов"
type="teaching"
/>
<ForTeachingOption
title="cоздание VR лабораторий"
description="Тренажер для проведения лабораториных работ позволит избежать
поломки оборудования, а также экономить на расходных средствах"
type="labs"
/>
<p className="font-medium lg:text-2xl sm:text-xl">
Оснащение учебных классов и центров всем необходимым для
современного обучения под «ключ»
</p>
</div>
export function ForTeachingTab() {
return (
<div
itemProp="forEducation"
itemScope
itemType="https://schema.org/TrainingsForEducation"
className="overflow-hidden lg:px-10 lg:pt-10 sm:px-6 sm:pt-6 px-4 pt-4 bg-[#14161F] border-y border-[#3D425C]"
>
<div className="flex justify-between">
<h2 className="font-medium h2">
Интерактивные тренажеры для учебных заведений
</h2>
<p className="h3 font-medium text-[#3D425C]">03</p>
</div>
<div className="flex justify-between max-sm:flex-col">
<div className="sm:max-w-[calc(500/768*100vw)] mt-6">
<div itemProp="creating" className="space-y-4 lg:max-w-[40vw] flex-1">
<ForTeachingOption
title="cоздание обучающих VR систем"
description="Проведение виртуальных практических работ, создание учебных мастерских и стендов"
type="teaching"
/>
<ForTeachingOption
title="cоздание VR лабораторий"
description="Тренажер для проведения лабораториных работ позволит избежать
поломки оборудования, а также экономить на расходных средствах"
type="labs"
/>
<p className="font-medium lg:text-2xl sm:text-xl">
Оснащение учебных классов и центров всем необходимым для
современного обучения под «ключ»
</p>
</div>
</div>
<img
src="/images/products/teaching/teaching.png"
className="max-sm:hidden w-[calc(685/1600*100vw)] sm:self-start lg:-mr-10 sm:-mr-6 -mr-4"
alt="обучение"
/>
<img
src="/images/products/teaching/teaching_mobile.png"
className="mt-5 -mx-6 sm:hidden"
alt="обучение"
/>
</div>
<img
src="/images/products/teaching/teaching.png"
className="max-sm:hidden w-[calc(685/1600*100vw)] sm:self-start"
alt="обучение"
/>
<img
src="/images/products/teaching/teaching_mobile.png"
className="mt-5 -mx-6 sm:hidden"
alt="обучение"
/>
</div>
</div>
));
);
}
function ForTeachingOption({
title,
@@ -1,4 +1,4 @@
import { forwardRef, useRef } from 'react';
import { useRef } from 'react';
import { getIcon } from '../../../../utils/getIcon';
import { useInView } from 'framer-motion';
@@ -35,33 +35,24 @@ function TeachingItem({
);
}
export const IndustrialTab = forwardRef<HTMLDivElement, { sticked: boolean }>(
({ sticked }, ref) => (
export function IndustrialTab() {
return (
<div
itemProp="industrial"
itemScope
itemType="https://schema.org/IndustrialTrainings"
ref={ref}
className="sm:sticky top-0 min-h-[100vh] min-w-[100vw] lg:px-10 lg:pt-10 sm:px-6 sm:pt-6 px-4 pt-4 border-t border-[#3D425C] bg-[#14161F] max-sm:flex flex-col items-center gap-y-4"
className="lg:px-10 lg:py-10 sm:px-6 sm:py-6 px-4 py-4 border-t border-[#3D425C] bg-[#14161F] overflow-hidden space-y-6 lg:space-y-14 sm:space-y-10"
>
<div className="space-y-6 lg:space-y-14 sm:space-y-10">
<div
className={
'flex justify-between items-center' +
(sticked ? ' sm:text-[#3D425C] transition-colors' : '')
}
>
<h2 className="w-full font-medium h2">Промышленные тренажеры</h2>
<p className="h3 font-medium text-[#3D425C]">01</p>
</div>
<div className="flex items-center justify-between">
<h2 className="w-full font-medium h2">Промышленные тренажеры</h2>
<p className="h3 font-medium text-[#3D425C]">01</p>
</div>
<div className="flex justify-between max-sm:items-center max-sm:flex-col">
<div
itemProp="education"
itemScope
itemType="https://schema.org/IndustrialTrainingsEducation"
className={
'sm:space-y-7 space-y-4 xl:max-w-[max(450px,calc(507/1600*100vw))] lg:max-w-[440px] sm:max-w-[calc(379/768*100vw)]' +
(sticked ? ' transition-opacity sm:opacity-0' : ' opacity-100')
}
className="sm:space-y-7 space-y-4 xl:max-w-[max(450px,calc(507/1600*100vw))] lg:max-w-[440px] sm:max-w-[calc(379/768*100vw)]"
>
<TeachingItem
iconType="danger"
@@ -79,28 +70,24 @@ export const IndustrialTab = forwardRef<HTMLDivElement, { sticked: boolean }>(
title="обучение правилам промышленной безопасности и охраны труда"
/>
</div>
<div className="relative bottom-0 lg:left-10 sm:left-6 left-4 lg:top-10 sm:top-6 top-4">
<img
src="/images/products/trainings/trainings_desktop.png"
className="object-cover lg:w-[calc(1000/1600*100vw)] xl:max-w-[calc(1152/1600*100vw)] max-lg:hidden"
alt="тренажеры"
/>
<img
src="/images/products/trainings/trainings_tablet.png"
className="object-cover w-[calc(438/768*100vw)] hidden sm:max-lg:block "
alt="тренажеры"
/>
<img
src="/images/products/trainings/trainings_mobile.png"
className="object-center aobject-cover sm:hidden"
alt="тренажеры"
/>
</div>
</div>
<img
src="/images/products/trainings/trainings_desktop.png"
className={
'absolute right-0 top-[121px] object-cover lg:w-[calc(1000/1600*100vw)] xl:w-[calc(1152/1600*100vw)] max-lg:hidden ' +
(sticked ? 'transition-opacity sm:opacity-0' : 'opacity-100')
}
alt="тренажеры"
/>
<img
src="/images/products/trainings/trainings_tablet.png"
className={
'absolute right-0 top-[120px] object-cover w-[calc(438/768*100vw)] hidden sm:max-lg:block ' +
(sticked ? 'transition-opacity sm:opacity-0' : 'opacity-100')
}
alt="тренажеры"
/>
<img
src="/images/products/trainings/trainings_mobile.png"
className="object-cover object-center sm:hidden"
alt="тренажеры"
/>
</div>
),
);
);
}
@@ -1,28 +1,20 @@
import { forwardRef } from 'react';
function SimulatorsItem({ text }: { text: string }) {
return (
<div className="text-sm bg-[#3D425C4D] rounded-[44px] w-fit sm:px-5 sm:py-2 px-4 py-1.5">
<div className="l-text bg-[#3D425C4D] rounded-[44px] w-fit sm:px-5 sm:py-2 px-4 py-1.5">
{text}
</div>
);
}
export const SimulatorsTab = forwardRef<HTMLDivElement, { sticked: boolean }>(
({ sticked }, ref) => (
export function SimulatorsTab() {
return (
<div
itemScope
itemProp="simulators"
itemType="http://schema.org/Simulators"
ref={ref}
className="lg:ml-[65px] lg:h-[85dvh] lg:min-w-[calc(100vw-65px)] sm:h-[90vh] min-w-[100vw] sm:sticky lg:top-[15vh] sm:top-[10vh] top-0 bg-[#14161F] lg:px-10 lg:pt-10 sm:px-6 sm:pt-6 px-4 pt-4 sm:space-y-10 space-y-6 lg:border-l border-t border-[#3D425C]"
className="bg-[#14161F] lg:px-10 lg:py-10 sm:px-6 sm:py-6 px-4 py-4 sm:space-y-10 space-y-6 border-t border-[#3D425C]"
>
<div
className={
'flex justify-between gap-x-2' +
(sticked ? ' text-[#3D425C] transition-colors' : '')
}
>
<div className="flex justify-between gap-x-2">
<h2 className="font-medium h2">Симуляторы управления техникой</h2>
<p className="text-[#3D425C] h3 font-medium">02</p>
</div>
@@ -30,10 +22,7 @@ export const SimulatorsTab = forwardRef<HTMLDivElement, { sticked: boolean }>(
itemProp="simulatorsTypes"
itemScope
itemType="http://schema.org/SimulatorsTypes"
className={
'flex flex-wrap gap-2 lg:max-w-[1000px]' +
(sticked ? ' transition-opacity sm:opacity-0' : ' opacity-100')
}
className="flex flex-wrap gap-2 lg:max-w-[1000px]"
>
<SimulatorsItem text="авиационные симуляторы" />
<SimulatorsItem text="погрузчики – ричстракеры" />
@@ -46,10 +35,7 @@ export const SimulatorsTab = forwardRef<HTMLDivElement, { sticked: boolean }>(
itemProp="simulatorsModel"
itemScope
itemType="http://schema.org/SimulatorsModel"
className={
'sm:flex max-sm:space-y-6 gap-x-2' +
(sticked ? ' transition-opacity sm:opacity-0' : ' opacity-100')
}
className="sm:flex max-sm:space-y-6 gap-x-2"
>
<div className="space-y-[10px] lg:w-[calc(400/1600*100vw)] sm:w-[calc(331/768*100vw)]">
<img
@@ -76,5 +62,5 @@ export const SimulatorsTab = forwardRef<HTMLDivElement, { sticked: boolean }>(
</div>
</div>
</div>
),
);
);
}
+4 -60
View File
@@ -1,74 +1,18 @@
import { useEffect, useRef, useState } from 'react';
import { ForTeachingTab } from './Tabs/ForTeachingTab';
import { SimulatorsTab } from './Tabs/SimulatorsTab';
import { IndustrialTab } from './Tabs/IndustrialTab';
export function Products() {
const ref1 = useRef<HTMLDivElement>(null);
const ref2 = useRef<HTMLDivElement>(null);
const ref3 = useRef<HTMLDivElement>(null);
const [stiked1, setSticked1] = useState(false);
const [stiked2, setSticked2] = useState(false);
function handleMouseMove(e: WheelEvent) {
setSticked1(
ref2.current!.getBoundingClientRect().top <=
+window.getComputedStyle(ref2.current!).top.slice(0, -2),
);
setSticked2(
ref3.current!.getBoundingClientRect().top <=
+window.getComputedStyle(ref3.current!).top.slice(0, -2),
);
if (e.deltaY > 0) {
if (
ref1.current!.getBoundingClientRect().top ===
+window.getComputedStyle(ref1.current!).top.slice(0, -2) &&
ref2.current!.getBoundingClientRect().top !==
+window.getComputedStyle(ref2.current!).top.slice(0, -2)
) {
window.scrollBy({
behavior: 'smooth',
top:
ref2.current!.getBoundingClientRect().top -
+window.getComputedStyle(ref2.current!).top.slice(0, -2),
});
setSticked1(true);
}
if (
Math.round(
ref2.current!.getBoundingClientRect().top -
+window.getComputedStyle(ref2.current!).top.slice(0, -2),
) === 0
) {
window.scrollBy({
top:
ref3.current!.getBoundingClientRect().top -
+window.getComputedStyle(ref3.current!).top.slice(0, -2),
});
setSticked2(true);
}
}
}
useEffect(() => {
window?.addEventListener('wheel', handleMouseMove);
return () => {
window?.removeEventListener('wheel', handleMouseMove);
};
}, [ref1, ref2, ref3]);
return (
<div
id="products"
itemScope
itemType="http://schema.org/Products"
className="xl:pt-[72px] pt-16 max-sm:py-14 lg:-mx-10 sm:-mx-6 -mx-4 sm:space-y-[500px] space-y-10 overflow-clip"
className="xl:pt-[70px] pt-[50px] max-sm:py-14 lg:-mx-10 sm:-mx-6 -mx-4"
>
<IndustrialTab ref={ref1} sticked={stiked1} />
<SimulatorsTab ref={ref2} sticked={stiked2} />
<ForTeachingTab ref={ref3} />
<IndustrialTab />
<SimulatorsTab />
<ForTeachingTab />
</div>
);
}
+2 -2
View File
@@ -2,7 +2,7 @@ import { useRef } from 'react';
import { IProject, Media } from '../../types/IProject';
export function Project({ src, title, tags, media, year }: IProject<Media>) {
const ref = useRef<HTMLVideoElement>(null);
const videoRef = useRef<HTMLVideoElement>(null);
return (
<div
@@ -22,7 +22,7 @@ export function Project({ src, title, tags, media, year }: IProject<Media>) {
) : (
<div className="flex flex-1">
<video
ref={ref}
ref={videoRef}
src={src}
muted
loop
+1 -1
View File
@@ -12,7 +12,7 @@ export function Projects() {
id="projects"
itemScope
itemType="https://schema.org/Projects"
className="lg:space-y-14 space-y-6 lg:pt-[100px] py-14"
className="lg:space-y-14 space-y-6 lg:pt-[100px] max-lg:py-16"
>
<Title className="lg:w-4/5">
<span className="text-gradient">Большой опыт в работе</span>{' '}
+1 -1
View File
@@ -11,7 +11,7 @@ export function Trainings() {
itemScope
itemType="http://schema.org/TrainingsEquipments"
id="trainings"
className="lg:py-[70px] py-14"
className="lg:py-[70px] py-16"
>
<Title className="2xl:mb-[77px] lg:mb-14 mb-6 lg:w-4/5 min-[2500px]:w-[70%]">
Предлагаем различные{' '}
+7
View File
@@ -7,6 +7,7 @@ export const projects: IProject<Media>[] = [
title: 'Симулятор погрузчика',
media: Media.img,
year: '2024',
id: Math.random(),
},
{
year: '2024',
@@ -14,6 +15,7 @@ export const projects: IProject<Media>[] = [
src: '/video/operator.mp4',
tags: ['Симулятор', 'VR-приложение'],
title: 'Обучение работе с системой водоочистки',
id: Math.random(),
} as IProject<Media.video>,
{
src: '/images/projects/plane.jpg',
@@ -21,6 +23,7 @@ export const projects: IProject<Media>[] = [
title: 'L 410 NG Aircraft',
year: '2024',
media: Media.img,
id: Math.random(),
},
{
src: '/images/projects/hangar.jpg',
@@ -28,6 +31,7 @@ export const projects: IProject<Media>[] = [
tags: ['Симулятор', 'VR-приложение'],
title: 'Сборка-разборка вертолётного двигателя',
media: Media.img,
id: Math.random(),
},
{
src: '/images/projects/trains.jpg',
@@ -35,6 +39,7 @@ export const projects: IProject<Media>[] = [
tags: ['Симулятор', 'VR-приложение'],
title: 'Тренажер РЖД: ЭП2Д, Иволга, ЭП20, ТЭ33А, ТЭМ2',
media: Media.img,
id: Math.random(),
},
{
src: '/images/projects/laboratory.jpg',
@@ -42,6 +47,7 @@ export const projects: IProject<Media>[] = [
title: 'Учебная лаборатория определения жирности молока',
year: '2024',
media: Media.img,
id: Math.random(),
},
{
src: '/images/projects/train_big.jpg',
@@ -49,5 +55,6 @@ export const projects: IProject<Media>[] = [
tags: ['Симулятор'],
title: 'Симулятор машиниста',
media: Media.img,
id: Math.random(),
},
];
+1
View File
@@ -9,4 +9,5 @@ export interface IProject<TMedia extends Media> {
tags: string[];
year: string;
media: TMedia;
id: number;
}
+52 -49
View File
@@ -4,7 +4,7 @@ import { ReactNode, useEffect, useReducer, useRef, useState } from 'react';
import { useSwipeable } from 'react-swipeable';
import { SliderControls } from '../components/Main/SliderControls';
export function SliderWithScaling<T extends { title: string }>({
export function SliderWithScaling<T extends { title: string; id: number }>({
slides,
SlideElement,
className = '',
@@ -31,7 +31,6 @@ export function SliderWithScaling<T extends { title: string }>({
const [transiting, setTransiting] = useState(false);
const [sliderOffset, setSliderOffset] = useState(baseoffset);
// const sliderRef = useRef<HTMLDivElement>(null);
const controlsRef = useRef<{ left: () => void; right: () => void }>({
left: () => {},
right: () => {},
@@ -44,36 +43,27 @@ export function SliderWithScaling<T extends { title: string }>({
case 'prev':
setSlide(slide => (slide === 0 ? slides.length - 1 : slide - 1));
setSliderOffset(3 * baseoffset);
return [state[state.length - 5], ...state.slice(0, -1)];
return [
{ ...state[state.length - 5], id: Math.random() },
...state.slice(0, -1),
];
case 'next':
setSlide(slide => (slide + 1) % slides.length);
setSliderOffset(baseoffset);
return [...state.slice(1), state[4]];
return [...state.slice(1), { ...state[4], id: Math.random() }];
default:
return state;
}
},
[
slides[slides.length - 2],
slides[slides.length - 1],
{ ...slides[slides.length - 2], id: Math.random() },
{ ...slides[slides.length - 1], id: Math.random() },
...slides,
slides[0],
slides[1],
{ ...slides[0], id: Math.random() },
{ ...slides[1], id: Math.random() },
],
);
function nextSlide() {
if (!transiting) {
dispatch('next');
}
}
function prevSlide() {
if (!transiting) {
dispatch('prev');
}
}
useEffect(() => {
setSliderOffset(2 * baseoffset);
}, [baseoffset, order, slide]);
@@ -86,6 +76,18 @@ export function SliderWithScaling<T extends { title: string }>({
touchEventOptions: { passive: false },
});
function nextSlide() {
if (!transiting) {
dispatch('next');
}
}
function prevSlide() {
if (!transiting) {
dispatch('prev');
}
}
return (
<div className={'flex flex-col relative ' + className}>
<div className="h-full -mx-4 overflow-hidden lg:-mx-10 sm:-mx-6">
@@ -100,36 +102,37 @@ export function SliderWithScaling<T extends { title: string }>({
transform: `translateX(${sliderOffset}px)`,
transitionDuration: `${sliderOffset !== baseoffset && sliderOffset !== 3 * baseoffset && sliderOffset !== 0 ? 1 : 0}s`,
}}
// ref={sliderRef}
>
{order.map((currentSlide, index) => (
<motion.div
key={
currentSlide.title +
(index < 2 ? '123' : index > slides.length ? '456' : '')
}
initial={
index === 1
? { minWidth: minWidthScaled, minHeight: minHeightScaled }
: { minWidth, minHeight }
}
transition={{ duration: 1, type: 'just' }}
animate={
index === 2
? {
minWidth: minWidthScaled,
minHeight: minHeightScaled,
}
: {
minWidth,
minHeight,
}
}
className={'cursor-pointer ' + childClassName}
>
<SlideElement {...currentSlide} />
</motion.div>
))}
{order.map((currentSlide, index) => {
return (
<motion.div
key={currentSlide.id}
initial={
index === 1
? {
minWidth: minWidthScaled,
minHeight: minHeightScaled,
}
: { minWidth, minHeight }
}
transition={{ duration: 1, type: 'just' }}
animate={
index === 2
? {
minWidth: minWidthScaled,
minHeight: minHeightScaled,
}
: {
minWidth,
minHeight,
}
}
className={'cursor-pointer ' + childClassName}
>
<SlideElement {...currentSlide} />
</motion.div>
);
})}
</div>
</div>
</div>