224 lines
9.0 KiB
TypeScript
224 lines
9.0 KiB
TypeScript
import { useState } from 'react'
|
||
import { motion, useMotionValueEvent, useScroll } from "motion/react"
|
||
import TypingEffect from './components/TypingEffect'
|
||
import CardsSection from './components/CardsSection'
|
||
import Section from './components/Section'
|
||
import Marquee from './components/Marquee'
|
||
import Navbar from './components/Navbar'
|
||
import ServicesSection from './components/ServicesSection'
|
||
import ProductsSection from './components/ProductsSection'
|
||
import CaseSection from './components/CaseSection'
|
||
import Footer from './components/Footer'
|
||
import AboutSection from './components/AboutSection'
|
||
import LicenseSection from './components/LicenseSection'
|
||
import MissionSection from './components/MissionSection'
|
||
import { TypingSpan } from './components/TypingSpan'
|
||
import DirectorSection from './components/DirectorSection'
|
||
|
||
function App() {
|
||
const { scrollY } = useScroll()
|
||
const [hidden, setHidden] = useState(false)
|
||
const [isAtTop, setIsAtTop] = useState(true)
|
||
|
||
useMotionValueEvent(scrollY, "change", (current) => {
|
||
const previous = scrollY.getPrevious() ?? 0
|
||
|
||
setIsAtTop(current === 0)
|
||
|
||
if (current > previous && current > 150) {
|
||
setHidden(true)
|
||
} else {
|
||
setHidden(false)
|
||
}
|
||
})
|
||
|
||
const partners = [
|
||
{
|
||
src: '/xkvadrat.svg'
|
||
},
|
||
{
|
||
src: '/rcit-BccMYqhE.svg'
|
||
},
|
||
{
|
||
src: '/vodokanal.svg'
|
||
},
|
||
{
|
||
src: '/tesaldan.svg'
|
||
},
|
||
{
|
||
src: '/tehnopark.svg'
|
||
},
|
||
{
|
||
src: '/sakhaspectrans-xe6pCR8Q.svg'
|
||
},
|
||
{
|
||
src: '/jkhsakha.svg'
|
||
},
|
||
]
|
||
|
||
const handleLink = () => {
|
||
const modal = document.getElementById('my_modal_2')
|
||
if (modal) {
|
||
(modal as HTMLDialogElement).close()
|
||
}
|
||
}
|
||
|
||
const languages = ['/python.svg', '/csharp.svg', '/js.svg', '/1c.svg']
|
||
const programs = ['/1c_franch.svg', '/astralinux.svg', '/drweb.svg', '/kasperskylab.svg']
|
||
|
||
return (
|
||
<main className='w-full flex flex-col sm:gap-8 items-center'>
|
||
<dialog id="my_modal_2" className="modal modal-end">
|
||
<div className="modal-box w-3/4 flex flex-col gap-8">
|
||
<div className='flex flex-row justify-between items-center'>
|
||
<div className="logo">
|
||
<img className="dark:invert dark:hue-rotate-180" width={180} src='/logo-commit.png' />
|
||
</div>
|
||
<form method="dialog">
|
||
<button className="btn btn-sm btn-circle btn-ghost p-2 text-2xl">✕</button>
|
||
</form>
|
||
</div>
|
||
|
||
<form method="dialog" className='flex flex-col gap-4'>
|
||
<a onClick={handleLink} href="#about" className='text-xl text-gray-500 hover:text-blue-500'>О компании</a>
|
||
<a onClick={handleLink} href="#products" className='text-xl text-gray-500 hover:text-blue-500'>Программные продукты</a>
|
||
<a onClick={handleLink} href="#services" className='text-xl text-gray-500 hover:text-blue-500'>Услуги</a>
|
||
<a onClick={handleLink} href="#case" className='text-xl text-gray-500 hover:text-blue-500'>Главный кейс</a>
|
||
<a onClick={handleLink} href="#contacts" className='text-xl text-gray-500 hover:text-blue-500'>Контакты</a>
|
||
</form>
|
||
</div>
|
||
<form method="dialog" className="modal-backdrop backdrop-blur-xs">
|
||
<button>close</button>
|
||
</form>
|
||
</dialog>
|
||
|
||
<Section>
|
||
<div className='h-full flex flex-col'>
|
||
<motion.header
|
||
className={`top-0 left-0 right-0 w-full backdrop-blur-2xl flex justify-center`}
|
||
initial={{ opacity: '0' }}
|
||
whileInView={{ opacity: '1' }}
|
||
>
|
||
<Navbar />
|
||
</motion.header>
|
||
|
||
<motion.header
|
||
className={`${isAtTop ? 'hidden' : ''} z-10 w-full fixed top-0 left-0 right-0 backdrop-blur-lg bg-base-100/70 flex justify-center`}
|
||
animate={{
|
||
y: hidden ? -140 : 0,
|
||
opacity: hidden ? 0 : 1,
|
||
}}
|
||
transition={{ duration: 0.3, ease: "easeInOut" }}
|
||
>
|
||
<Navbar />
|
||
</motion.header>
|
||
|
||
<div className='relative grid sm:grid-cols-2 h-auto grow gap-8 rounded-2xl bg-base-200 p-8'>
|
||
<div className='z-1 h-auto grow flex flex-col gap-4'>
|
||
<span className='text-xs text-gray-500 bg-base-100 rounded-2xl p-2 flex justify-center'>Все наши специалисты имеют профессиональное образование и опыт более 15 лет работы</span>
|
||
|
||
<div className='text-3xl grid grid-rows-[repeat(4,1fr)] md:grid-rows-[1fr_1fr]'>
|
||
<span className='row-span-2 md:row-span-1'>Программное обеспечение</span>
|
||
<div className='row-span-2 inline-flex flex-wrap w-full text-blue-400 h-min'>
|
||
<TypingSpan typingSpeed={40} deletingSpeed={20} pauseTime={2000} />
|
||
</div>
|
||
{/* <span> — полный цикл разработки и технической поддержки</span> */}
|
||
</div>
|
||
|
||
<span className='text-gray-500'>
|
||
Берём ответственность за ваши ИТ-решения, снимая риски и операционную нагрузку, выступая надёжным технологическим партнёром по разработке и сопровождению
|
||
</span>
|
||
|
||
<div className='flex flex-col gap-4'>
|
||
<span className='text-xs text-gray-500'>
|
||
✳︎ Работаем с такими языками программирования, как:
|
||
</span>
|
||
|
||
<div className='flex flex-row'>
|
||
{languages.map((lang, index) => (
|
||
<div key={index} style={{ marginLeft: index === 0 ? '' : '-0.5rem' }} className='border-2 border-base-200 w-12.5 h-12.5 flex justify-center items-center p-2 rounded-full overflow-hidden bg-white'>
|
||
<img src={lang} />
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
<span className='text-xs text-gray-500'>
|
||
✳︎ Работаем с такими программами, как:
|
||
</span>
|
||
|
||
<div className='flex flex-row'>
|
||
{programs.map((lang, index) => (
|
||
<div key={index} style={{ marginLeft: index === 0 ? '' : '-0.5rem' }} className='border-2 border-base-200 w-12.5 h-12.5 flex justify-center items-center p-2 rounded-full overflow-hidden bg-white'>
|
||
<img src={lang} />
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className='absolute blur-xs sm:blur-none inset-0 sm:relative h-full w-full p-4'>
|
||
<TypingEffect text={`/*
|
||
Совет из продакшена:
|
||
если код "гениальный" — готовься его переписывать.
|
||
если код простой — скорее всего, он переживёт тебя.
|
||
*/
|
||
@font-face {
|
||
font-family: "HiddenFont";
|
||
src: local("Arial");
|
||
unicode-range: U+043F, U+043E, U+043C, U+043E, U+0433, U+0430, U+0435,
|
||
U+043C, U+0020, U+0441, U+0020, U+0440, U+0430, U+0437,
|
||
U+0440, U+0430, U+0431, U+043E, U+0442, U+043A, U+043E,
|
||
U+0439, U+043E, U+045E, U+048E, U+056E, U+068E, U+069E,
|
||
U+070E, U+074E, U+077E, U+079E, U+081E, U+083E, U+086E,
|
||
U+089E, U+091E, U+094E, U+095E, U+098E, U+099E, U+0533,
|
||
U+0536, U+0539, U+0555, U+0563, U+781, U+783, U+789;
|
||
|
||
body {
|
||
margin: 0;
|
||
font-family: Arial, sans-serif;
|
||
}
|
||
|
||
Если ты это читаешь:
|
||
— сборка прошла
|
||
— багов нет
|
||
/*
|
||
мы помогаем с разработкой программного обеспечения
|
||
и бережно сопровождаем на всех этапах работ
|
||
/*
|
||
|
||
TODO: не удалять — это не хаос, это философия */
|
||
`} speed={0.01} />
|
||
<div className='absolute inset-0 bg-linear-to-b from-base-200 to-transparent'></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</Section>
|
||
|
||
<CardsSection />
|
||
|
||
<AboutSection />
|
||
|
||
<div className="w-full overflow-hidden select-none py-8 bg-base-200">
|
||
<Marquee speed={20} items={partners} from={0} to={"-100%"} />
|
||
</div>
|
||
|
||
<DirectorSection />
|
||
|
||
<MissionSection />
|
||
|
||
<ProductsSection />
|
||
|
||
<ServicesSection />
|
||
|
||
<LicenseSection />
|
||
|
||
<CaseSection />
|
||
|
||
<Footer />
|
||
</main>
|
||
)
|
||
}
|
||
|
||
export default App
|