Initial commit: Сисадмингрупп website

React + Vite + Tailwind, RU/EN, Hero/Services/About/Contact sections
This commit is contained in:
2026-03-14 01:02:02 +03:00
parent b3cb94d01b
commit abff3fa4cc
19 changed files with 2834 additions and 0 deletions

195
src/pages/Home.jsx Normal file
View File

@@ -0,0 +1,195 @@
import React, { useState } from 'react'
import { ChevronRight, Server, Shield, Headphones, Phone, Mail, MapPin, CheckCircle2 } from 'lucide-react'
import { useLanguage } from '../contexts/LanguageContext.jsx'
import { useReveal } from '../components/useReveal.js'
const serviceIcons = [Server, Shield, Headphones]
function ServiceCard({ icon: Icon, title, description, points }) {
const ref = useReveal()
return (
<div ref={ref} className="section-reveal bg-white border border-slate-200 rounded-xl p-8 hover:shadow-lg hover:border-blue-200 transition-all duration-300 flex flex-col gap-4">
<div className="w-12 h-12 bg-blue-50 rounded-lg flex items-center justify-center">
<Icon size={24} className="text-blue-700" />
</div>
<h3 className="text-xl font-bold text-slate-900">{title}</h3>
<p className="text-slate-600 text-sm leading-relaxed">{description}</p>
<ul className="flex flex-col gap-2 mt-auto pt-4 border-t border-slate-100">
{points.map((p, i) => (
<li key={i} className="flex items-center gap-2 text-sm text-slate-700">
<CheckCircle2 size={16} className="text-blue-600 flex-shrink-0" />
{p}
</li>
))}
</ul>
</div>
)
}
export default function Home() {
const { t } = useLanguage()
const [formState, setFormState] = useState({ name: '', company: '', message: '' })
const [submitted, setSubmitted] = useState(false)
const aboutRef = useReveal()
const contactRef = useReveal()
const services = t('services.items')
const stats = [t('about.stat1'), t('about.stat2'), t('about.stat3')]
const handleSubmit = (e) => {
e.preventDefault()
setSubmitted(true)
}
return (
<div>
{/* Hero */}
<section className="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-900 via-blue-950 to-slate-900 relative overflow-hidden">
<div className="absolute inset-0 opacity-20">
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-blue-500 rounded-full blur-3xl" />
<div className="absolute bottom-1/4 right-1/4 w-80 h-80 bg-blue-700 rounded-full blur-3xl" />
</div>
<div className="max-w-4xl mx-auto px-4 sm:px-6 py-32 text-center relative z-10">
<div className="inline-flex items-center gap-2 bg-blue-500/10 border border-blue-500/20 rounded-full px-4 py-1.5 mb-8">
<div className="w-2 h-2 bg-blue-400 rounded-full animate-pulse" />
<span className="text-blue-300 text-sm font-medium">IT-аутсорсинг · Безопасность · Поддержка</span>
</div>
<h1 className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold text-white leading-tight mb-6">
{t('hero.title')}
</h1>
<p className="text-lg sm:text-xl text-slate-300 max-w-2xl mx-auto mb-10 leading-relaxed">
{t('hero.subtitle')}
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<a href="#contact" className="px-8 py-4 bg-blue-600 hover:bg-blue-500 text-white font-semibold rounded-lg transition-all duration-300 flex items-center justify-center gap-2 group">
{t('hero.cta')}
<ChevronRight size={20} className="group-hover:translate-x-1 transition-transform" />
</a>
<a href="#services" className="px-8 py-4 border border-white/20 hover:border-white/40 text-white font-semibold rounded-lg transition-all duration-300">
{t('hero.ctaSecondary')}
</a>
</div>
</div>
</section>
{/* Services */}
<section id="services" className="py-24 bg-slate-50">
<div className="max-w-6xl mx-auto px-4 sm:px-6">
<div className="text-center mb-16">
<h2 className="text-3xl sm:text-4xl md:text-5xl font-bold text-slate-900 mb-4">{t('services.title')}</h2>
<p className="text-slate-500 text-lg max-w-2xl mx-auto">{t('services.subtitle')}</p>
</div>
<div className="grid md:grid-cols-3 gap-6">
{services.map((svc, i) => (
<ServiceCard key={i} icon={serviceIcons[i]} {...svc} />
))}
</div>
</div>
</section>
{/* About */}
<section id="about" className="py-24 bg-white">
<div className="max-w-6xl mx-auto px-4 sm:px-6">
<div ref={aboutRef} className="section-reveal grid md:grid-cols-2 gap-16 items-center">
<div>
<h2 className="text-3xl sm:text-4xl font-bold text-slate-900 mb-6">{t('about.title')}</h2>
<p className="text-slate-600 text-lg leading-relaxed mb-4">{t('about.text1')}</p>
<p className="text-slate-600 leading-relaxed">{t('about.text2')}</p>
</div>
<div className="grid grid-cols-3 gap-4">
{stats.map((s, i) => (
<div key={i} className="bg-slate-50 rounded-xl p-6 text-center border border-slate-100">
<div className="text-3xl font-bold text-blue-700 mb-1">{s.value}</div>
<div className="text-sm text-slate-500">{s.label}</div>
</div>
))}
</div>
</div>
</div>
</section>
{/* Contact */}
<section id="contact" className="py-24 bg-slate-900">
<div className="max-w-6xl mx-auto px-4 sm:px-6">
<div ref={contactRef} className="section-reveal grid md:grid-cols-2 gap-16">
<div>
<h2 className="text-3xl sm:text-4xl font-bold text-white mb-4">{t('contact.title')}</h2>
<p className="text-slate-400 text-lg mb-10">{t('contact.subtitle')}</p>
<div className="flex flex-col gap-6">
<div className="flex items-center gap-4">
<div className="w-10 h-10 bg-blue-500/10 rounded-lg flex items-center justify-center flex-shrink-0">
<Phone size={20} className="text-blue-400" />
</div>
<div>
<div className="text-slate-400 text-xs uppercase tracking-wider mb-0.5">{t('contact.phone')}</div>
<a href="tel:+74953637476" className="text-white font-medium hover:text-blue-400 transition-colors">+7 495 363-74-76</a>
</div>
</div>
<div className="flex items-center gap-4">
<div className="w-10 h-10 bg-blue-500/10 rounded-lg flex items-center justify-center flex-shrink-0">
<Mail size={20} className="text-blue-400" />
</div>
<div>
<div className="text-slate-400 text-xs uppercase tracking-wider mb-0.5">{t('contact.email')}</div>
<a href="mailto:info@sag24.ru" className="text-white font-medium hover:text-blue-400 transition-colors">info@sag24.ru</a>
</div>
</div>
<div className="flex items-center gap-4">
<div className="w-10 h-10 bg-blue-500/10 rounded-lg flex items-center justify-center flex-shrink-0">
<MapPin size={20} className="text-blue-400" />
</div>
<div>
<div className="text-slate-400 text-xs uppercase tracking-wider mb-0.5">{t('contact.address')}</div>
<span className="text-white font-medium">{t('contact.addressValue')}</span>
</div>
</div>
</div>
</div>
<div className="bg-white/5 border border-white/10 rounded-xl p-8">
{submitted ? (
<div className="flex flex-col items-center justify-center h-full gap-4 py-8">
<CheckCircle2 size={48} className="text-green-400" />
<p className="text-white text-center text-lg">{t('contact.formSuccess')}</p>
</div>
) : (
<form onSubmit={handleSubmit} className="flex flex-col gap-4">
<input
type="text"
required
placeholder={t('contact.formName')}
value={formState.name}
onChange={e => setFormState({ ...formState, name: e.target.value })}
className="w-full bg-white/10 border border-white/10 rounded-lg px-4 py-3 text-white placeholder-slate-400 focus:outline-none focus:border-blue-500 transition-colors text-sm"
/>
<input
type="text"
placeholder={t('contact.formCompany')}
value={formState.company}
onChange={e => setFormState({ ...formState, company: e.target.value })}
className="w-full bg-white/10 border border-white/10 rounded-lg px-4 py-3 text-white placeholder-slate-400 focus:outline-none focus:border-blue-500 transition-colors text-sm"
/>
<textarea
required
rows={5}
placeholder={t('contact.formMessage')}
value={formState.message}
onChange={e => setFormState({ ...formState, message: e.target.value })}
className="w-full bg-white/10 border border-white/10 rounded-lg px-4 py-3 text-white placeholder-slate-400 focus:outline-none focus:border-blue-500 transition-colors text-sm resize-none"
/>
<button
type="submit"
className="w-full py-3 bg-blue-600 hover:bg-blue-500 text-white font-semibold rounded-lg transition-colors"
>
{t('contact.formSubmit')}
</button>
</form>
)}
</div>
</div>
</div>
</section>
</div>
)
}