This commit is contained in:
2025-09-26 14:11:24 +05:00
parent 80b1c9108e
commit e990cf666e
18 changed files with 150 additions and 150 deletions
+2 -1
View File
@@ -14,5 +14,6 @@ module.exports = {
'warn', 'warn',
{ allowConstantExport: true }, { allowConstantExport: true },
], ],
'no-irregular-whitespace': 'off',
}, },
} };
+3 -3
View File
@@ -11,13 +11,13 @@ export function Footer() {
<div className="flex flex-col gap-y-1"> <div className="flex flex-col gap-y-1">
<NavLink <NavLink
to="/policy" to="/policy"
className="flex gap-4 outline-none sm:font-medium m-text" className="sm:font-medium m-text flex gap-4 outline-none"
target="_blank" target="_blank"
> >
Политика конфиденциальности <span>graff.tech</span> Политика конфиденциальности <span>graff.tech</span>
</NavLink> </NavLink>
<p className="opacity-40 sm:font-medium m-text"> <p className="sm:font-medium m-text opacity-40">
© 2024 GRAFF interactive. Все права защищены © 2025 GRAFF interactive. Все права защищены
</p> </p>
</div> </div>
</div> </div>
+27 -31
View File
@@ -2,17 +2,14 @@ import { motion } from 'framer-motion';
import { PropsWithChildren, useRef, useState } from 'react'; import { PropsWithChildren, useRef, useState } from 'react';
import { AnchorLink } from '../../ui/AnchorLink'; import { AnchorLink } from '../../ui/AnchorLink';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { useLanguageStore } from '../../store/languageStore';
import { useOnClickOutside } from 'usehooks-ts'; import { useOnClickOutside } from 'usehooks-ts';
import { useModalStore } from '../../store/modalStore'; import { useModalStore } from '../../store/modalStore';
import { ModalWithForm } from '../Main/ModalWithForm'; import { ModalWithForm } from '../Main/ModalWithForm';
import { Button } from '../../ui/Button'; import { Button } from '../../ui/Button';
import { LogoWithTextIcon } from '../icons/LogoWithTextIcon'; import { LogoWithTextIcon } from '../icons/LogoWithTextIcon';
import { LogoIcon } from '../icons/LogoIcon';
import { BurgerIcon } from '../icons/BurgerIcon'; import { BurgerIcon } from '../icons/BurgerIcon';
import { CloseIcon } from '../icons/CloseIcon'; import { CloseIcon } from '../icons/CloseIcon';
import { CubeIcon } from '../icons/CubeIcon'; import { CubeIcon } from '../icons/CubeIcon';
import { useWindowWidth } from '../../hooks/useWindowWidth';
export function Header() { export function Header() {
const [menuOpen, setMenuOpen] = useState(false); const [menuOpen, setMenuOpen] = useState(false);
@@ -25,14 +22,11 @@ export function Header() {
() => setMenuOpen(false), () => setMenuOpen(false),
); );
const width = useWindowWidth();
return ( return (
<header className="sticky top-0 z-[90] w-full bg-[#14161F]"> <header className="sticky top-0 z-[90] w-full bg-[#14161F]">
<nav className="flex justify-between border-b border-[#3D425C] lg:pl-10 pl-4 xl:max-h-[72px] max-h-16"> <nav className="flex justify-between border-b border-[#3D425C] lg:pl-10 pl-4 xl:max-h-[72px] max-h-16">
<Link to={'/'} className="flex items-center outline-none"> <Link to={'/'} className="flex items-center outline-none">
<LogoIcon className="lg:hidden" /> <LogoWithTextIcon className="w-[104px]" />
{width >= 1024 && <LogoWithTextIcon className="w-[104px]" />}
</Link> </Link>
<div className="flex mx-auto"> <div className="flex mx-auto">
<AnchorLink route="#products">Типы тренажеров</AnchorLink> <AnchorLink route="#products">Типы тренажеров</AnchorLink>
@@ -41,7 +35,7 @@ export function Header() {
</div> </div>
<Button <Button
onClick={() => setModal(<ModalWithForm />)} onClick={() => setModal(<ModalWithForm />)}
className="px-10 font-semibold rounded-none btn-text max-sm:hidden" className="btn-text max-sm:hidden px-10 font-semibold rounded-none"
> >
Оставить заявку Оставить заявку
</Button> </Button>
@@ -51,7 +45,9 @@ export function Header() {
onClick={() => setMenuOpen(prev => !prev)} onClick={() => setMenuOpen(prev => !prev)}
className="p-5 xl:hidden border-[#3D425C] max-sm:border-l outline-none" className="p-5 xl:hidden border-[#3D425C] max-sm:border-l outline-none"
> >
{!menuOpen ? <BurgerIcon /> : <CloseIcon />} <div className="size-6">
{!menuOpen ? <BurgerIcon /> : <CloseIcon />}
</div>
</button> </button>
</nav> </nav>
<motion.div <motion.div
@@ -72,20 +68,20 @@ export function Header() {
<BurgerAnchor route="#products">Типы тренажеров</BurgerAnchor> <BurgerAnchor route="#products">Типы тренажеров</BurgerAnchor>
<BurgerAnchor route="#projects">Проекты</BurgerAnchor> <BurgerAnchor route="#projects">Проекты</BurgerAnchor>
<BurgerAnchor route="#trainings">Варианты комплектации</BurgerAnchor> <BurgerAnchor route="#trainings">Варианты комплектации</BurgerAnchor>
</div>
<div className="grid grid-cols-[2fr_1fr_1fr] sm:grid-cols-2">
<Button <Button
onClick={() => { onClick={() => {
setMenuOpen(false); setMenuOpen(false);
setModal(<ModalWithForm />); setModal(<ModalWithForm />);
}} }}
width="full" width="full"
className="font-semibold rounded-none outline-none sm:hidden btn-text" className="sm:hidden btn-text py-6 font-semibold rounded-none outline-none"
> >
Оставить заявку Оставить заявку
</Button> </Button>
<ChooseLang currentLang="RU" /> </div>
<ChooseLang currentLang="EN" /> <div className="gridgrid-cols-[2fr_1fr_1fr] sm:grid-cols-2">
{/* <ChooseLang currentLang="RU" />
<ChooseLang currentLang="EN" /> */}
</div> </div>
</motion.div> </motion.div>
</header> </header>
@@ -107,23 +103,23 @@ function BurgerAnchor({
); );
} }
function ChooseLang({ currentLang }: { currentLang: 'RU' | 'EN' }) { // function ChooseLang({ currentLang }: { currentLang: 'RU' | 'EN' }) {
const { setLang, lang } = useLanguageStore(); // const { setLang, lang } = useLanguageStore();
return ( // return (
<button // <button
onClick={() => setLang(currentLang)} // onClick={() => setLang(currentLang)}
className={ // className={
'min-h-[72px] w-full h-full btn-text font-semibold bg-[#14161F] sm:hover:bg-[#3D425C] border active:bg-[#14161F] outline-none ' + // 'min-h-[72px] w-full h-full btn-text font-semibold bg-[#14161F] sm:hover:bg-[#3D425C] border active:bg-[#14161F] outline-none ' +
(lang === currentLang // (lang === currentLang
? '[border-image:linear-gradient(to_right,#798FFF,#D375FF)_3]' // ? '[border-image:linear-gradient(to_right,#798FFF,#D375FF)_3]'
: 'border-[#3D425C]') // : 'border-[#3D425C]')
} // }
> // >
{currentLang} // {currentLang}
</button> // </button>
); // );
} // }
// function LangToggler({ lang }: { lang: Lang }) { // function LangToggler({ lang }: { lang: Lang }) {
// const [open, setOpen] = useState(false); // const [open, setOpen] = useState(false);
@@ -139,7 +135,7 @@ function ChooseLang({ currentLang }: { currentLang: 'RU' | 'EN' }) {
// <button // <button
// ref={langTogglerRef} // ref={langTogglerRef}
// onClick={() => setOpen(prev => !prev)} // onClick={() => setOpen(prev => !prev)}
// className="flex items-center h-full mx-6 font-semibold outline-none gap-x-1 btn-text" // className="btn-text flex gap-x-1 items-center mx-6 h-full font-semibold outline-none"
// > // >
// {lang} // {lang}
// <ChevronDownIcon /> // <ChevronDownIcon />
+25 -25
View File
@@ -16,7 +16,7 @@ export function Contacts() {
return ( return (
<div className="sm:grid lg:grid-cols-12 sm:grid-cols-2 lg:gap-x-4 sm:gap-x-14 lg:gap-y-[68px] pb-20 pt-[70px]"> <div className="sm:grid lg:grid-cols-12 sm:grid-cols-2 lg:gap-x-4 sm:gap-x-14 lg:gap-y-[68px] pb-20 pt-[70px]">
<h2 className="lg:col-span-7 sm:col-span-full h2 max-lg:mb-6 font-medium"> <h2 className="lg:col-span-7 sm:col-span-full h2 max-lg:mb-6 font-medium">
Хотите использовать интерактивные тренажеры в обучении? Хотите использовать интерактивные тренажеры в обучении?
<br /> <br />
<span className="text-gradient">Давайте обсудим детали</span> <span className="text-gradient">Давайте обсудим детали</span>
</h2> </h2>
@@ -30,7 +30,7 @@ export function Contacts() {
/> />
</div> </div>
} }
className="lg:col-span-3 sm:max-lg:mb-20 max-sm:mb-14 self-end row-start-2 px-6 py-4" className="lg:col-span-3 sm:max-lg:mb-20 max-sm:mb-14 row-start-2 self-end px-6 py-4"
width="full" width="full"
onClick={() => setModal(<ModalWithForm />)} onClick={() => setModal(<ModalWithForm />)}
> >
@@ -38,32 +38,32 @@ export function Contacts() {
</Button> </Button>
<div className="lg:col-start-9 lg:col-span-4 sm:col-span-1 sm:col-start-1 max-sm:mb-8 space-y-3"> <div className="lg:col-start-9 lg:col-span-4 sm:col-span-1 sm:col-start-1 max-sm:mb-8 space-y-3">
<h4 className="mb-1 text-xl font-medium">Свяжитесь с нами</h4> <h4 className="mb-1 text-xl font-medium">Свяжитесь с нами</h4>
<Button <Link to={'mailto:info@graff.tech'} className="block">
color="secondary" <Button
className="py-4" color="secondary"
width="full" className="py-4"
icon={<ClassNameWrapper element={<MailIcon />} className="w-8 h-8" />} width="full"
onClick={() => { icon={
window.location.href = 'mailto:info@graff.tech'; <ClassNameWrapper element={<MailIcon />} className="w-8 h-8" />
}} }
> >
<span className="btn-text opacity-80">Написать</span> <span className="btn-text opacity-80">Написать</span>
</Button> </Button>
<Button </Link>
color="secondary" <Link to={'tel:88007700067'} className="block">
className="py-4" <Button
width="full" color="secondary"
icon={<PhoneIcon />} className="py-4"
onClick={() => { width="full"
window.location.href = 'tel:88007700067'; icon={<PhoneIcon />}
}} >
> <span className="btn-text opacity-80">Позвонить</span>
<span className="btn-text opacity-80">Позвонить</span> </Button>
</Button> </Link>
</div> </div>
<div className="lg:col-start-9 lg:col-span-4 lg:row-start-2 sm:row-start-3 lg:self-end sm:flex sm:flex-col sm:justify-between col-start-2 space-y-4"> <div className="lg:col-start-9 lg:col-span-4 lg:row-start-2 sm:row-start-3 lg:self-end sm:flex sm:flex-col sm:justify-between col-start-2 space-y-4">
<h4 className="h4 font-medium">Социальные сети</h4> <h4 className="h4 font-medium">Социальные сети</h4>
<div className="gap-x-2 flex"> <div className="flex gap-x-2">
<Link <Link
to={'https://www.youtube.com/@GRAFFtech'} to={'https://www.youtube.com/@GRAFFtech'}
className="p-4 rounded-full opacity-80 border-[#3D425C] border hover:border-[#52587A] transition-all" className="p-4 rounded-full opacity-80 border-[#3D425C] border hover:border-[#52587A] transition-all"
+6 -6
View File
@@ -17,21 +17,21 @@ export function Decreasing() {
</span>{' '} </span>{' '}
сделать обучение сотрудников безопасней и&nbsp;эффективней сделать обучение сотрудников безопасней и&nbsp;эффективней
</Title> </Title>
<div className="grid grid-cols-2 mt-6 lg:mt-14 gap-x-4 gap-y-6"> <div className="lg:mt-14 grid grid-cols-2 gap-x-4 gap-y-6 mt-6">
<div className="col-span-2 space-y-10 lg:col-start-1 sm:max-lg:col-start-1 xl:col-span-1"> <div className="lg:col-start-1 sm:max-lg:col-start-1 xl:col-span-1 col-span-2 space-y-10">
<div> <div>
{[ {[
'снижение количества несчастных случаев', 'снижение количества несчастных случаев',
'уменьшение количества ошибок при ТО и ППР', 'уменьшение количества ошибок при ТО и ППР',
'меньше случаев внеплановой остановки оборудования', 'меньше случаев внеплановой остановки оборудования',
'снижение расходов на закупку реальной техники и оборудования для обучения', 'снижение расходов на закупку реальной техники и оборудования для обучения',
'сокращение сроков обучения', 'сокращение сроков обучения',
].map((text, index) => ( ].map((text, index) => (
<DecreasingOption key={index} text={text} number={index + 1} /> <DecreasingOption key={index} text={text} number={index + 1} />
))} ))}
</div> </div>
<Button <Button
className="w-full py-4 text-xl font-bold xl:w-1/2 lg:w-1/3 sm:w-1/2" className="xl:w-1/2 lg:w-1/3 sm:w-1/2 py-4 w-full text-xl font-bold"
icon={ icon={
<div className="p-2 bg-white rounded-full"> <div className="p-2 bg-white rounded-full">
<ClassNameWrapper <ClassNameWrapper
@@ -72,12 +72,12 @@ function DecreasingOption({ text, number }: { text: string; number: number }) {
return ( return (
<div className="group"> <div className="group">
<AppearanceHr delay={number * 0.5} /> <AppearanceHr delay={number * 0.5} />
<div className="flex items-center justify-between py-5 gap-x-4"> <div className="flex gap-x-4 justify-between items-center py-5">
<Plus text={text} /> <Plus text={text} />
<Number number={number} /> <Number number={number} />
</div> </div>
<AppearanceHr <AppearanceHr
className="hidden group-last:block" className="group-last:block hidden"
delay={(number + 1) * 0.5} delay={(number + 1) * 0.5}
/> />
</div> </div>
+8 -8
View File
@@ -8,24 +8,24 @@ export function Distance() {
className="lg:py-[100px] py-14" className="lg:py-[100px] py-14"
> >
<Title className="lg:w-4/5 lg:mb-14 mb-6"> <Title className="lg:w-4/5 lg:mb-14 mb-6">
Платформа GRAFF.training позволяет осуществлять Платформа GRAFF.training позволяет осуществлять
<span className="text-gradient"> дистанционное обучение</span>{' '} <span className="text-gradient"> дистанционное обучение</span> с любого
с&nbsp;любого устройства устройства
</Title> </Title>
<div className="sm:grid lg:grid-cols-12 gap-x-4 gap-y-6"> <div className="sm:grid lg:grid-cols-12 gap-x-4 gap-y-6">
<p className="lg:col-start-1 max-sm:mb-6 col-span-6 row-start-1 text-xl"> <p className="lg:col-start-1 max-sm:mb-6 col-span-6 row-start-1 text-xl">
Обучающиеся будут получать доступ к системе с высоко детализированной Обучающиеся будут получать доступ к системе с высокодетализированной
3D графикой для прохождения сценариев на любом устройстве, без 3D&#8209;графикой для прохождения сценариев на любом устройстве,
необходимости установки дополнительного ПО. без необходимости установки дополнительного ПО.
</p> </p>
<div className="lg:col-start-1 max-sm:mb-4 self-stretch col-span-6 row-start-2"> <div className="lg:col-start-1 max-sm:mb-4 col-span-6 row-start-2 self-stretch">
<img <img
src="/images/distance/datamining_2.jpg" src="/images/distance/datamining_2.jpg"
alt="дистанционное обучение с любого устройства" alt="дистанционное обучение с любого устройства"
className="object-cover object-[bottom_-1px_left_-1px]" className="object-cover object-[bottom_-1px_left_-1px]"
/> />
</div> </div>
<div className="lg:col-start-7 lg:col-span-6 self-stretch col-span-3 row-start-2"> <div className="lg:col-start-7 lg:col-span-6 col-span-3 row-start-2 self-stretch">
<img <img
src="/images/distance/datamining_1.jpg" src="/images/distance/datamining_1.jpg"
alt="дистанционное обучение с любого устройства" alt="дистанционное обучение с любого устройства"
+7 -7
View File
@@ -7,7 +7,7 @@ import { useWindowWidth } from '../../hooks/useWindowWidth';
export function Effeciency() { export function Effeciency() {
return ( return (
<div className="lg:py-[70px] py-14"> <div className="lg:py-[70px] py-14">
<div className="pt-5 gap-x-4 gap-y-8 sm:grid lg:grid-cols-12 sm:grid-cols-8 max-sm:space-y-6"> <div className="sm:grid lg:grid-cols-12 sm:grid-cols-8 max-sm:space-y-6 gap-x-4 gap-y-8 pt-5">
<MiniTitle <MiniTitle
text={'экономическая эффективность'} text={'экономическая эффективность'}
className="col-span-3" className="col-span-3"
@@ -16,7 +16,7 @@ export function Effeciency() {
<Figure <Figure
percents={50} percents={50}
type="charts" type="charts"
title={'сокращение бюджета на обучение сотрудников'} title={'сокращение бюджета на обучение сотрудников'}
/> />
<Figure <Figure
percents={30} percents={30}
@@ -26,24 +26,24 @@ export function Effeciency() {
<Figure <Figure
percents={90} percents={90}
type="pizza" type="pizza"
title={'готовность к опасным ситуациям выше на'} title={'готовность к опасным ситуациям выше на'}
/> />
</div> </div>
<AppearanceText <AppearanceText
className="row-start-3 lg:col-span-6 col-span-full" className="lg:col-span-6 col-span-full row-start-3"
splits={[ splits={[
'В тренажере человек ', 'В тренажере человек ',
'принимает решения ', 'принимает решения ',
'так же, ', 'так же, ',
'как в реальном мире, ', 'как в реальном мире, ',
'активируя ', 'активируя ',
'те же нейронные ', 'те же нейронные ',
'цепочки в мозгу. ', 'цепочки в мозгу. ',
'Это позволяет ', 'Это позволяет ',
'добиться ', 'добиться ',
'реальной ', 'реальной ',
'производительности ', 'производительности ',
работе. ',  работе. ',
]} ]}
/> />
</div> </div>
+8 -6
View File
@@ -101,13 +101,15 @@ export function ModalWithForm() {
<div className="fixed flex flex-col gap-4 top-0 right-0 h-full sm:w-[408px] w-full bg-[#14161F] overflow-y-auto sm:p-8 p-6"> <div className="fixed flex flex-col gap-4 top-0 right-0 h-full sm:w-[408px] w-full bg-[#14161F] overflow-y-auto sm:p-8 p-6">
{!isSend ? ( {!isSend ? (
<div className="space-y-8"> <div className="space-y-8">
<div className="flex items-center justify-between"> <div className="flex justify-between items-center">
<p className="font-medium accent">Оставьте заявку</p> <p className="accent font-medium">Оставьте заявку</p>
<button <button
onClick={() => setModal(null)} onClick={() => setModal(null)}
className="p-2 transition-colors rounded-full lg:hover:bg-white lg:hover:bg-opacity-10" className="lg:hover:bg-white lg:hover:bg-opacity-10 p-2 rounded-full transition-colors"
> >
<CloseIcon /> <div className="size-6">
<CloseIcon />
</div>
</button> </button>
</div> </div>
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
@@ -154,7 +156,7 @@ export function ModalWithForm() {
value={phone} value={phone}
placeholder={placeholder} placeholder={placeholder}
onChange={e => setPhone(e.target.value.replace(/ /g, ''))} onChange={e => setPhone(e.target.value.replace(/ /g, ''))}
className="w-full transition-all bg-transparent rounded-none outline-none h4 placeholder:h4 placeholder:font-medium placeholder:select-none peer" className="h4 placeholder:h4 placeholder:font-medium placeholder:select-none peer w-full bg-transparent rounded-none transition-all outline-none"
/> />
<div className="bottom-0 absolute w-full border-b border-[#3D425C] peer-focus:border-white -mb-2" /> <div className="bottom-0 absolute w-full border-b border-[#3D425C] peer-focus:border-white -mb-2" />
</div> </div>
@@ -237,7 +239,7 @@ export function ModalWithForm() {
) : ( ) : (
<div className=""> <div className="">
<div className="space-y-8"> <div className="space-y-8">
<h2 className="font-medium h2">Спасибо за отправку заявки!</h2> <h2 className="h2 font-medium">Спасибо за отправку заявки!</h2>
<p className="m-text"> <p className="m-text">
Мы ценим ваш интерес к нашей компании и в ближайшее время свяжемся Мы ценим ваш интерес к нашей компании и в ближайшее время свяжемся
с вами для уточнения деталей проекта. с вами для уточнения деталей проекта.
+5 -5
View File
@@ -1,15 +1,15 @@
export function Motivation() { export function Motivation() {
return ( return (
<div> <div>
<div className="grid grid-cols-12 lg:py-28 sm:py-12 py-14"> <div className="lg:py-28 sm:py-12 grid grid-cols-12 py-14">
<h1 className="2xl:mb-[38px] pb-8 font-medium lg:block max-lg:hidden h1 col-span-full"> <h1 className="2xl:mb-[38px] pb-8 font-medium max-lg:hidden h1 col-span-full">
Создаем Создаем
<span className="text-gradient"> интерактивные тренажеры </span> <span className="text-gradient"> интерактивные тренажеры </span>
для промышленности и&nbsp;образования для промышленности и&nbsp;образования
</h1> </h1>
<h1 className="font-medium lg:hidden h1 col-span-full"> <h1 className="lg:hidden h1 col-span-full font-medium">
Интерактивные тренажеры Интерактивные тренажеры
<span className="text-gradient"> для обучения сотрудников</span> <span className="text-gradient"> для обучения сотрудников</span>
</h1> </h1>
<h3 className="lg:col-span-full max-lg:hidden h3"> <h3 className="lg:col-span-full max-lg:hidden h3">
Помогаем сократить затраты на обучение, повысить безопасность и Помогаем сократить затраты на обучение, повысить безопасность и
+5 -5
View File
@@ -12,7 +12,7 @@ export function MultiUser() {
itemType="http://schema.org/MultiUser" itemType="http://schema.org/MultiUser"
className="lg:py-[100px] py-14 sm:grid lg:grid-cols-12 sm:grid-cols-3" className="lg:py-[100px] py-14 sm:grid lg:grid-cols-12 sm:grid-cols-3"
> >
<Title className="row-start-1 mb-6 lg:mb-14 col-span-full"> <Title className="lg:mb-14 col-span-full row-start-1 mb-6">
<span className="text-gradient text-wrap">Многопользовательский </span> <span className="text-gradient text-wrap">Многопользовательский </span>
<br className="lg:hidden" /> <br className="lg:hidden" />
режим обучения режим обучения
@@ -22,15 +22,15 @@ export function MultiUser() {
itemProp="multiUserFeatures" itemProp="multiUserFeatures"
itemScope itemScope
itemType="http://schema.org/MultiUserFeatures" itemType="http://schema.org/MultiUserFeatures"
className="grid max-lg:col-span-full sm:max-lg:row-start-2 lg:col-span-6 lg:row-span-2 lg:grid-cols-2 sm:grid-cols-3 lg:-mr-10 max-lg:-mx-6" className="max-lg:col-span-full sm:max-lg:row-start-2 lg:col-span-6 lg:row-span-2 lg:grid-cols-2 sm:grid-cols-3 lg:-mr-10 max-lg:-mx-6 grid"
> >
<MultiUserFeature <MultiUserFeature
type="processes" type="processes"
text="отработка производственных процессов, в которых участвует группа людей" text="отработка производственных процессов, в которых участвует группа людей"
/> />
<MultiUserFeature <MultiUserFeature
type="plans" type="plans"
text="командная отработка планов мероприятий по локализации и ликвидации последствий аварий" text="командная отработка планов мероприятий по локализации и ликвидации последствий аварий"
/> />
<MultiUserFeature <MultiUserFeature
type="teamwork" type="teamwork"
@@ -39,7 +39,7 @@ export function MultiUser() {
</div> </div>
<div className="lg:hidden lg:col-span-6 col-start-1 lg:row-span-2 sm:col-span-3 lg:row-start-2 sm:row-start-3 sm:row-span-1 bg-[url(/images/availables/image.jpg)] bg-cover bg-no-repeat bg-center sm:aspect-[728/356] aspect-[3/2] max-sm:-mx-6" /> <div className="lg:hidden lg:col-span-6 col-start-1 lg:row-span-2 sm:col-span-3 lg:row-start-2 sm:row-start-3 sm:row-span-1 bg-[url(/images/availables/image.jpg)] bg-cover bg-no-repeat bg-center sm:aspect-[728/356] aspect-[3/2] max-sm:-mx-6" />
<AppearanceText <AppearanceText
className="col-span-7 col-start-1 mt-8 lg:col-span-6 max-lg:mt-6" className="lg:col-span-6 max-lg:mt-6 col-span-7 col-start-1 mt-8"
splits={[ splits={[
'В одном ', 'В одном ',
'цифровом ', 'цифровом ',
@@ -29,23 +29,23 @@ export function ForTeachingTab() {
transition={{ duration: 1.5, delay: 0.5 }} transition={{ duration: 1.5, delay: 0.5 }}
className="flex justify-between" className="flex justify-between"
> >
<h2 className="font-medium h2"> <h2 className="h2 font-medium">
Интерактивные тренажеры для учебных заведений Интерактивные тренажеры для учебных заведений
</h2> </h2>
<p className="h3 font-medium text-[#3D425C]">03</p> <p className="h3 font-medium text-[#3D425C]">03</p>
</motion.div> </motion.div>
<div className="flex justify-between max-sm:flex-col"> <div className="max-sm:flex-col flex justify-between">
<div className="sm:max-w-[calc(500/768*100vw)] mt-6"> <div className="sm:max-w-[calc(500/768*100vw)] mt-6">
<div itemProp="creating" className="space-y-4 lg:max-w-[40vw] flex-1"> <div itemProp="creating" className="space-y-4 lg:max-w-[40vw] flex-1">
<ForTeachingOption <ForTeachingOption
title="cоздание обучающих VR систем" title="cоздание обучающих VR систем"
description="Проведение виртуальных практических работ, создание учебных мастерских и стендов" description="Проведение виртуальных практических работ, создание учебных мастерских и стендов"
type="teaching" type="teaching"
/> />
<ForTeachingOption <ForTeachingOption
title="cоздание VR лабораторий" title="cоздание VR лабораторий"
description="Тренажер для проведения лабораториных работ позволит избежать description="Тренажер для проведения лабораториных работ позволит избежать
поломки оборудования, а также экономить на расходных средствах" поломки оборудования, а также экономить на расходных средствах"
type="labs" type="labs"
/> />
<motion.p <motion.p
@@ -53,10 +53,10 @@ export function ForTeachingTab() {
initial={{ opacity: 0 }} initial={{ opacity: 0 }}
animate={textInView ? { opacity: 1 } : {}} animate={textInView ? { opacity: 1 } : {}}
transition={{ duration: 1, delay: 1 }} transition={{ duration: 1, delay: 1 }}
className="font-medium lg:text-2xl sm:text-xl" className="lg:text-2xl sm:text-xl font-medium"
> >
Оснащение учебных классов и центров всем необходимым для Оснащение учебных классов и центров всем необходимым
современного обучения под «ключ» для современного обучения «под ключ»
</motion.p> </motion.p>
</div> </div>
</div> </div>
@@ -65,7 +65,7 @@ export function ForTeachingTab() {
animate={imgInView ? { opacity: 1 } : {}} animate={imgInView ? { opacity: 1 } : {}}
transition={{ duration: 1, delay: 1 }} transition={{ duration: 1, delay: 1 }}
ref={imgRef} ref={imgRef}
className="mt-5 -mr-4 lg:-mr-10 sm:-mr-6 max-sm:-mx-6 max-sm:-mb-4" className="lg:-mr-10 sm:-mr-6 max-sm:-mx-6 max-sm:-mb-4 mt-5 -mr-4"
> >
<img <img
src="/images/products/teaching/teaching.png" src="/images/products/teaching/teaching.png"
@@ -74,7 +74,7 @@ export function ForTeachingTab() {
/> />
<img <img
src="/images/products/teaching/teaching_mobile.png" src="/images/products/teaching/teaching_mobile.png"
className="w-full mt-5 -mx-6 sm:hidden" className="sm:hidden -mx-6 mt-5 w-full"
alt="обучение" alt="обучение"
/> />
</motion.div> </motion.div>
@@ -105,11 +105,11 @@ function ForTeachingOption({
> >
{getIcon(type, true, 'max-sm:hidden min-w-11')} {getIcon(type, true, 'max-sm:hidden min-w-11')}
<div className="lg:pl-4 sm:pl-[13px] sm:border-l border-[#3D425C] w-[90%]"> <div className="lg:pl-4 sm:pl-[13px] sm:border-l border-[#3D425C] w-[90%]">
<div className="flex items-center mb-1 sm:items-start sm:max-lg:flex-col max-sm:gap-x-2"> <div className="sm:items-start sm:max-lg:flex-col max-sm:gap-x-2 flex items-center mb-1">
{getIcon(type, inView, 'sm:hidden min-w-11')} {getIcon(type, inView, 'sm:hidden min-w-11')}
<h4 className="font-medium lg:text-2xl sm:text-xl">{title}</h4> <h4 className="lg:text-2xl sm:text-xl font-medium">{title}</h4>
</div> </div>
<p className="opacity-60 l-text">{description}</p> <p className="l-text opacity-60">{description}</p>
</div> </div>
</motion.div> </motion.div>
); );
@@ -32,9 +32,9 @@ function TeachingItem({
> >
{getIcon(iconType, true, 'max-sm:hidden sm:max-lg:mb-[14px] min-w-11')} {getIcon(iconType, true, 'max-sm:hidden sm:max-lg:mb-[14px] min-w-11')}
<div className="sm:border-l border-[#3D425C] sm:pl-4"> <div className="sm:border-l border-[#3D425C] sm:pl-4">
<div className="flex items-center mb-2 max-sm:gap-x-2"> <div className="max-sm:gap-x-2 flex items-center mb-2">
{getIcon(iconType, rootInView, 'sm:hidden min-w-11')} {getIcon(iconType, rootInView, 'sm:hidden min-w-11')}
<h4 className="font-medium lg:text-2xl sm:text-xl">{title}</h4> <h4 className="lg:text-2xl sm:text-xl font-medium">{title}</h4>
</div> </div>
<p className="l-text opacity-60">{text}</p> <p className="l-text opacity-60">{text}</p>
</div> </div>
@@ -63,12 +63,12 @@ export function IndustrialTab() {
animate={{ opacity: titleInView ? 1 : 0 }} animate={{ opacity: titleInView ? 1 : 0 }}
transition={{ duration: 1, delay: 0.5 }} transition={{ duration: 1, delay: 0.5 }}
ref={titleRef} ref={titleRef}
className="flex items-center justify-between" className="flex justify-between items-center"
> >
<h2 className="w-full font-medium h2">Промышленные тренажеры</h2> <h2 className="h2 w-full font-medium">Промышленные тренажеры</h2>
<p className="h3 font-medium text-[#3D425C]">01</p> <p className="h3 font-medium text-[#3D425C]">01</p>
</motion.div> </motion.div>
<div className="flex justify-between max-sm:items-center max-sm:flex-col"> <div className="max-sm:items-center max-sm:flex-col flex justify-between">
<div <div
itemProp="education" itemProp="education"
itemScope itemScope
@@ -77,20 +77,20 @@ export function IndustrialTab() {
> >
<TeachingItem <TeachingItem
iconType="danger" iconType="danger"
text="отработка проведения технологических операций: оказание первой помощи, работы на высоте, работа с доменной печью и т.п." text="отработка проведения технологических операций: оказание первой помощи, работы на высоте, работа с доменной печью и т.п."
title="обучение навыкам работы на опасных производствах" title="обучение навыкам работы на опасных производствах"
index={0} index={0}
/> />
<TeachingItem <TeachingItem
iconType="service" iconType="service"
text="отработка определения неисправностей оборудования и выполнения ремонтных работ на цифровом двойнике" text="отработка определения неисправностей оборудования и выполнения ремонтных работ на цифровом двойнике"
title="обучение обслуживанию и ремонту оборудования, систем, техники" title="обучение обслуживанию и ремонту оборудования, систем, техники"
index={1} index={1}
/> />
<TeachingItem <TeachingItem
iconType="safety" iconType="safety"
text="отработка плана мероприятий по локализации и ликвидации последствий аварий. " text="отработка плана мероприятий по локализации и ликвидации последствий аварий"
title="обучение правилам промышленной безопасности и охраны труда" title="обучение правилам промышленной безопасности и охраны труда"
index={2} index={2}
/> />
</div> </div>
@@ -99,7 +99,7 @@ export function IndustrialTab() {
initial={{ opacity: 0 }} initial={{ opacity: 0 }}
animate={imgInView ? { opacity: 1 } : {}} animate={imgInView ? { opacity: 1 } : {}}
transition={{ duration: 1, delay: 1 }} transition={{ duration: 1, delay: 1 }}
className="relative bottom-0 lg:left-10 sm:left-6 left-4 lg:top-10 sm:top-6 top-4" className="lg:left-10 sm:left-6 lg:top-10 sm:top-6 relative bottom-0 top-4 left-4"
> >
<img <img
src="/images/products/trainings/trainings_desktop.png" src="/images/products/trainings/trainings_desktop.png"
@@ -113,7 +113,7 @@ export function IndustrialTab() {
/> />
<img <img
src="/images/products/trainings/trainings_mobile.png" src="/images/products/trainings/trainings_mobile.png"
className="object-cover object-center sm:hidden" className="sm:hidden object-cover object-center"
alt="тренажеры" alt="тренажеры"
/> />
</motion.div> </motion.div>
@@ -40,9 +40,9 @@ export function SimulatorsTab() {
initial={{ opacity: 0 }} initial={{ opacity: 0 }}
animate={titleInView ? { opacity: 1 } : {}} animate={titleInView ? { opacity: 1 } : {}}
transition={{ duration: 1, delay: 0.5 }} transition={{ duration: 1, delay: 0.5 }}
className="flex justify-between gap-x-2" className="flex gap-x-2 justify-between"
> >
<h2 className="font-medium h2">Симуляторы управления техникой</h2> <h2 className="h2 font-medium">Симуляторы управления техникой</h2>
<p className="text-[#3D425C] h3 font-medium">02</p> <p className="text-[#3D425C] h3 font-medium">02</p>
</motion.div> </motion.div>
<div <div
@@ -94,8 +94,8 @@ export function SimulatorsTab() {
/> />
<p className="l-text opacity-60"> <p className="l-text opacity-60">
Модель позволяет производить расчеты характеристик работы, Модель позволяет производить расчеты характеристик работы,
отслеживать безопасность работы устройств и симулировать внештатные отслеживать безопасность работы устройств и симулировать внештатные
ситуации. ситуации
</p> </p>
</motion.div> </motion.div>
</div> </div>
+6 -6
View File
@@ -15,8 +15,8 @@ export function Teaching() {
координацию между всеми участниками процесса координацию между всеми участниками процесса
</Title> </Title>
<Title className="2xl:mb-[29px] lg:hidden mb-6 col-span-full"> <Title className="2xl:mb-[29px] lg:hidden mb-6 col-span-full">
<span className="text-gradient">Дистанционное обучение</span> на базе <span className="text-gradient">Дистанционное обучение</span> на базе
платформы GRAFF TRANING платформы GRAFF.training
</Title> </Title>
<TeachingFeaturesForDesktop /> <TeachingFeaturesForDesktop />
<TeachingFeaturesForOtherScreens /> <TeachingFeaturesForOtherScreens />
@@ -79,8 +79,8 @@ function TeachingFeaturesForDesktop() {
<div className="space-y-2 max-w-[calc(410/752*100%)]"> <div className="space-y-2 max-w-[calc(410/752*100%)]">
<TeachingFeatureTitle>Видеозапись обучения</TeachingFeatureTitle> <TeachingFeatureTitle>Видеозапись обучения</TeachingFeatureTitle>
<TeachingFeatureDescription> <TeachingFeatureDescription>
Фиксация и хранение сессий обучения, тренировки и тестирования. Фиксация и хранение сессий обучения, тренировки и тестирования.
Ретроспектива по пройденной сессии вместе с инструктором Ретроспектива по пройденной сессии вместе с инструктором
</TeachingFeatureDescription> </TeachingFeatureDescription>
</div> </div>
<img <img
@@ -155,8 +155,8 @@ function TeachingFeaturesForOtherScreens() {
<div className="space-y-1"> <div className="space-y-1">
<TeachingFeatureTitle>Видеозапись обучения</TeachingFeatureTitle> <TeachingFeatureTitle>Видеозапись обучения</TeachingFeatureTitle>
<TeachingFeatureDescription className="sm:max-w-[calc(305/768*100vw)]"> <TeachingFeatureDescription className="sm:max-w-[calc(305/768*100vw)]">
Фиксация и хранение сессий обучения, тренировки и тестирования. Фиксация и хранение сессий обучения, тренировки и тестирования.
Ретроспектива по пройденной сессии вместе с инструктором Ретроспектива по пройденной сессии вместе с инструктором
</TeachingFeatureDescription> </TeachingFeatureDescription>
</div> </div>
<img <img
+15 -12
View File
@@ -14,33 +14,36 @@ export function Trainings() {
className="lg:py-[70px] py-16" className="lg:py-[70px] py-16"
> >
<Title className="2xl:mb-[77px] lg:mb-14 mb-6 lg:w-4/5 min-[2500px]:w-[70%]"> <Title className="2xl:mb-[77px] lg:mb-14 mb-6 lg:w-4/5 min-[2500px]:w-[70%]">
Предлагаем различные{' '} Предлагаем различные
<span className="text-gradient">варианты комплектации тренажеров</span>, <span className="text-gradient">
основываясь на специфике вашего тренировочного процесса {' '}
варианты комплектации тренажеров,{' '}
</span>
основываясь на специфике вашего тренировочного процесса
</Title> </Title>
<div <div
itemType="http://schema.org/TrainingsEquipmentsFeatures" itemType="http://schema.org/TrainingsEquipmentsFeatures"
itemScope itemScope
itemProp="features" itemProp="features"
className="sm:grid lg:grid-cols-12 gap-x-4 grid-cols-8" className="sm:grid lg:grid-cols-12 grid-cols-8 gap-x-4"
> >
<TrainingsFeature <TrainingsFeature
order={1} order={1}
src="/images/trainings/vr.png" src="/images/trainings/vr.png"
title="VR - тренажеры" title="VR - тренажеры"
text="Обучение навыкам работы с инструментами и оборудованием. Пешее хождение по территории или между оборудованием" text="Обучение навыкам работы с инструментами и оборудованием. Пешее хождение по территории или между оборудованием"
/> />
<TrainingsFeature <TrainingsFeature
order={2} order={2}
src="/images/trainings/stand.png" src="/images/trainings/stand.png"
title="Cтенды" title="Cтенды"
text="Отработки навыков вождения и управления техникой. Работа с панелями управления" text="Отработки навыков вождения и управления техникой. Работа с панелями управления"
/> />
<TrainingsFeature <TrainingsFeature
order={3} order={3}
src="/images/trainings/classroom.png" src="/images/trainings/classroom.png"
title="Учебные классы" title="Учебные классы"
text="Оснащение учебных классов и центров всем необходимым для современного обучения и профессиональной подготовки кадров" text="Оснащение учебных классов и центров всем необходимым для современного обучения и профессиональной подготовки кадров"
/> />
</div> </div>
</div> </div>
@@ -66,7 +69,7 @@ function TrainingsFeature({
itemProp={title} itemProp={title}
itemScope itemScope
itemType={`http://schema.org/${title}`} itemType={`http://schema.org/${title}`}
className="lg:col-start-1 col-span-full group" className="lg:col-start-1 group col-span-full"
> >
<AppearanceHr delay={0.5 * order} /> <AppearanceHr delay={0.5 * order} />
<div <div
@@ -75,9 +78,9 @@ function TrainingsFeature({
> >
<div className="sm:space-y-4 lg:w-1/3 sm:w-1/2 col-span-1"> <div className="sm:space-y-4 lg:w-1/3 sm:w-1/2 col-span-1">
<h3 className="max-sm:mb-2 h3 font-medium">{title}</h3> <h3 className="max-sm:mb-2 h3 font-medium">{title}</h3>
<p className="opacity-60 l-text">{text}</p> <p className="l-text opacity-60">{text}</p>
</div> </div>
<div className="sm:hidden flex items-end justify-between"> <div className="sm:hidden flex justify-between items-end">
<p className="text-[#52587A] m-text mb-5">[0{order}]</p> <p className="text-[#52587A] m-text mb-5">[0{order}]</p>
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<img src={src} alt={title} className="relative z-30 w-[50vw]" /> <img src={src} alt={title} className="relative z-30 w-[50vw]" />
@@ -91,7 +94,7 @@ function TrainingsFeature({
transition={{ transition={{
duration: 0.4, duration: 0.4,
}} }}
className="lg:flex items-center justify-center hidden -my-10" className="lg:flex hidden justify-center items-center -my-10"
> >
<img <img
src={src} src={src}
@@ -100,7 +103,7 @@ function TrainingsFeature({
/> />
<VrBacklightIcon className="absolute w-[24vw]" /> <VrBacklightIcon className="absolute w-[24vw]" />
</motion.div> </motion.div>
<div className="lg:hidden flex items-center justify-center"> <div className="lg:hidden flex justify-center items-center">
<img <img
src={src} src={src}
className="w-[27vw] relative z-20 h-[calc(27vw*0.6)]" className="w-[27vw] relative z-20 h-[calc(27vw*0.6)]"
-2
View File
@@ -1,8 +1,6 @@
export function BurgerIcon({ className = '' }: { className?: string }) { export function BurgerIcon({ className = '' }: { className?: string }) {
return ( return (
<svg <svg
width="24"
height="24"
viewBox="0 0 24 24" viewBox="0 0 24 24"
className={className} className={className}
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
+1 -1
View File
@@ -21,7 +21,7 @@ export const projects: IProject<Media>[] = [
src: '/images/projects/plane.jpg', src: '/images/projects/plane.jpg',
tags: ['Симулятор', 'VR-приложение'], tags: ['Симулятор', 'VR-приложение'],
title: 'L 410 NG Aircraft', title: 'L 410 NG Aircraft',
year: '2024', year: '2019',
media: Media.img, media: Media.img,
id: Math.random(), id: Math.random(),
}, },
+1 -1
View File
@@ -34,7 +34,7 @@ export function Button({
icon ? 'pr-4' : '' icon ? 'pr-4' : ''
} flex gap-1 items-center overflow-hidden w-${width} ${className} justify-between`} } flex gap-1 items-center overflow-hidden w-${width} ${className} justify-between`}
> >
<div className="absolute top-0 left-0 w-full h-full transition-opacity bg-black opacity-0 group-hover:opacity-10" /> <div className="group-hover:opacity-10 absolute top-0 left-0 w-full h-full bg-black opacity-0 transition-opacity" />
<span className={'relative font-medium' + (icon ? '' : ' m-auto')}> <span className={'relative font-medium' + (icon ? '' : ' m-auto')}>
{children} {children}
</span> </span>