Initial commit: Сисадмингрупп website
React + Vite + Tailwind, RU/EN, Hero/Services/About/Contact sections
This commit is contained in:
195
src/pages/Home.jsx
Normal file
195
src/pages/Home.jsx
Normal 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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user