Initial commit

This commit is contained in:
2026-02-10 16:22:14 +05:00
parent bc64b84640
commit 505f49fbd9
6720 changed files with 1357701 additions and 0 deletions

1
.env.local Normal file
View File

@@ -0,0 +1 @@
GEMINI_API_KEY=PLACEHOLDER_API_KEY

67
App.tsx Normal file
View File

@@ -0,0 +1,67 @@
import React, { useEffect } from 'react';
import { HashRouter as Router, Routes, Route, useLocation } from 'react-router-dom';
import Navbar from './components/Navbar';
import Footer from './components/Footer';
import ScrollToTopButton from './components/ScrollToTop';
import Home from './pages/Home';
import ServicesPage from './pages/ServicesPage';
import ProjectsPage from './pages/ProjectsPage';
import AboutPage from './pages/AboutPage';
import ContactsPage from './pages/ContactsPage';
import FleetPage from './pages/FleetPage';
import CertificatesPage from './pages/CertificatesPage';
import SurveyingPage from './pages/SurveyingPage';
import DesignPage from './pages/DesignPage';
import ConstructionPage from './pages/ConstructionPage';
import SoilSurveyPage from './pages/SoilSurveyPage';
import BuildingSurveyPage from './pages/BuildingSurveyPage';
import LandSurveyPage from './pages/LandSurveyPage';
import TechnicalTasksPage from './pages/TechnicalTasksPage';
import SoilLabPage from './pages/SoilLabPage';
import RadiationLabPage from './pages/RadiationLabPage';
import PrivacyPolicyPage from './pages/PrivacyPolicyPage';
// Scroll to top on route change
const ScrollToTop = () => {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return null;
};
const App: React.FC = () => {
return (
<Router>
<div className="w-full bg-white overflow-hidden font-sans flex flex-col min-h-screen">
<ScrollToTop />
<Navbar transparent={true} />
<main className="flex-grow">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/services" element={<ServicesPage />} />
<Route path="/services/surveying" element={<SurveyingPage />} />
<Route path="/services/design" element={<DesignPage />} />
<Route path="/services/construction" element={<ConstructionPage />} />
<Route path="/services/soil-survey" element={<SoilSurveyPage />} />
<Route path="/services/building-survey" element={<BuildingSurveyPage />} />
<Route path="/services/land-survey" element={<LandSurveyPage />} />
<Route path="/services/technical-tasks" element={<TechnicalTasksPage />} />
<Route path="/projects" element={<ProjectsPage />} />
<Route path="/fleet" element={<FleetPage />} />
<Route path="/laboratories/soil" element={<SoilLabPage />} />
<Route path="/laboratories/radiation" element={<RadiationLabPage />} />
<Route path="/certificates" element={<CertificatesPage />} />
<Route path="/about" element={<AboutPage />} />
<Route path="/contacts" element={<ContactsPage />} />
<Route path="/privacy-policy" element={<PrivacyPolicyPage />} />
</Routes>
</main>
<Footer />
<ScrollToTopButton />
</div>
</Router>
);
};
export default App;

249
FINAL_IMAGES_STATUS.md Normal file
View File

@@ -0,0 +1,249 @@
# ✅ Финальный статус изображений на сайте
## 🎉 ПОЛНОСТЬЮ УСТАНОВЛЕНО (27 изображений)
### ✅ Главная страница (1 изображение)
- **Hero Banner** → `/media/images/hero/hero-main.png`
- Размер: 1920×1080px
- Файл: `components/Hero.tsx`
### ✅ Заголовки всех страниц (14 изображений)
| Страница | Файл | Изображение |
|----------|------|------------|
| О компании | `pages/AboutPage.tsx` | `/media/images/headers/header-about.png` |
| Услуги | `pages/ServicesPage.tsx` | `/media/images/headers/header-services.png` |
| Проекты | `pages/ProjectsPage.tsx` | `/media/images/headers/header-projects.png` |
| Автопарк | `pages/FleetPage.tsx` | `/media/images/headers/header-fleet.png` |
| Сертификаты | `pages/CertificatesPage.tsx` | `/media/images/headers/header-certificates.png` |
| Контакты | `pages/ContactsPage.tsx` | `/media/images/headers/header-kontakri.png` |
| Инж. изыскания | `pages/SurveyingPage.tsx` | `/media/images/headers/header-injinernie-iziskania.png` |
| Проектирование | `pages/DesignPage.tsx` | `/media/images/headers/header-projectirovanie.png` |
| Строительство | `pages/ConstructionPage.tsx` | `/media/images/headers/header-building.png` |
| Обследование грунтов | `pages/SoilSurveyPage.tsx` | `/media/images/headers/header-obsledovanie-gruntov.png` |
| Обследование зданий | `pages/BuildingSurveyPage.tsx` | `/media/images/headers/header-observing-buildings.png` |
| Землеустройство | `pages/LandSurveyPage.tsx` | `/media/images/headers/header-zemlestroit-kadastr-jobs.png` |
| Грунтовая лаборатория | `pages/SoilLabPage.tsx` | `/media/images/headers/soil-lab-header.png` |
| Радиационная лаборатория | `pages/RadiationLabPage.tsx` | `/media/images/headers/radio-lab-header.png` |
| Технические задания | `pages/TechnicalTasksPage.tsx` | `/media/images/services/technical-assignments.png` |
Размер: 1920×600px (все заголовки)
### ✅ Услуги на главной (7 изображений)
| Услуга | Изображение |
|--------|------------|
| Технические задания | `/media/images/services/technical-assignments.png` |
| Инженерные изыскания | `/media/images/services/engineering-surveys.png` |
| Проектирование | `/media/images/services/design.png` |
| Строительство | `/media/images/services/construction.png` |
| Обследование грунтов | `/media/images/services/soil-survey.png` |
| Обследование здания | `/media/images/services/building-inspection.png` |
| Кадастровые работы | `/media/images/services/cadastral-works.png` |
Размер: 600×800px (вертикальные)
Файл: `constants.ts` → SERVICES
### ✅ О компании (2 изображения)
- **Офис** → `/media/images/about/office.png` (800×600px)
- **Команда** → `/media/images/about/team-work.png` (600×400px)
- Файл: `pages/AboutPage.tsx`
### ✅ Лаборатории (2 изображения - переиспользованы)
- **Грунтовая лаборатория** → `/media/images/services/soil-survey.png`
- **Радиационная лаборатория** → `/media/images/services/engineering-surveys.png`
- Файл: `components/Laboratories.tsx`
### ✅ Дефолтное изображение
- **По умолчанию** → `/media/images/headers/header-about.png`
- Файл: `components/PageHeader.tsx` (используется для страниц без явного изображения)
---
## ⏳ ОСТАЮТСЯ ПЛЕЙСХОЛДЕРЫ (117 изображений)
### 📁 1. ПРОЕКТЫ - 93 изображения (600×400px)
**Файл**: `constants.ts` → PROJECTS (строки 82-174)
**Текущее значение**: `https://placehold.co/600x400/94a3b8/white`
#### 📂 Рекомендуемая структура папок:
```
media/images/projects/
oil-gas/ (30 изображений)
residential/ (15 изображений)
infrastructure/ (20 изображений)
social/ (10 изображений)
industrial/ (15 изображений)
commercial/ (3 изображения)
```
#### 🎨 ПРОМПТЫ для категорий проектов:
**A. Нефтегазовая промышленность** (30 проектов)
```
Промпт:
Oil and gas industrial complex, refinery towers and pipelines,
modern petrochemical plant, industrial infrastructure with storage tanks,
professional industrial photography, wide shot, blue sky, realistic, high quality
```
**B. Жилищное строительство** (15 проектов)
```
Промпт:
Modern residential apartment building complex, multi-story housing project,
contemporary urban architecture, landscaped courtyard, professional real estate photography,
daylight, realistic style
```
**C. Инфраструктура и коммуникации** (20 проектов)
```
Промпт:
Infrastructure construction project, pipeline installation, utility networks,
gas pipeline or water supply system being built, modern engineering work,
construction equipment, professional photography
```
**D. Социальные объекты** (10 проектов)
```
Промпт:
Modern public building - school, kindergarten, or community center,
contemporary social infrastructure architecture, accessible design,
professional architectural photography, welcoming appearance
```
**E. Промышленные объекты** (15 проектов)
```
Промпт:
Industrial warehouse or production facility, modern factory building,
metal hangars, industrial architecture with steel structures,
professional industrial photography, clean and organized
```
**F. Коммерческая недвижимость** (3 проекта)
```
Промпт:
Modern commercial building, business center with glass facade,
contemporary office architecture, urban location, professional photography
```
#### 💡 БЫСТРОЕ РЕШЕНИЕ для проектов:
Вместо 93 уникальных изображений, создайте **6 базовых** (по одному на категорию):
- `project-oil-gas.jpg`
- `project-residential.jpg`
- `project-infrastructure.jpg`
- `project-social.jpg`
- `project-industrial.jpg`
- `project-commercial.jpg`
Затем я обновлю код, чтобы каждая категория использовала соответствующее изображение.
---
### 📜 2. СЕРТИФИКАТЫ - 24 изображения (400×600px)
**Файл**: `pages/CertificatesPage.tsx` (строки 23-86)
**Текущее значение**: `https://placehold.co/400x600/94a3b8/white`
#### 📂 Структура:
```
media/images/certificates/
cert-1.jpg - Сертификат КРЕДО
cert-2.jpg - СРО Строительство (док 1)
cert-3.jpg - СРО Строительство (док 2)
cert-4.jpg - СРО Строительство (док 3)
cert-5.jpg - СРО Строительство (док 4)
cert-6.jpg - СРО Проектирование (док 1)
cert-7.jpg - СРО Проектирование (док 2)
cert-8.jpg - СРО Изыскания (док 1)
cert-9.jpg - СРО Изыскания (док 2)
cert-10.jpg - Членство СРО Строительство (док 1)
cert-11.jpg - Членство СРО Строительство (док 2)
cert-12.jpg - Членство СРО Строительство (док 3)
cert-13.jpg - Членство СРО Проектирование (док 1)
cert-14.jpg - Членство СРО Проектирование (док 2)
cert-15.jpg - Членство СРО Изыскания (док 1)
cert-16.jpg - Членство СРО Изыскания (док 2)
cert-17.jpg - Допуск к опасным объектам (док 1)
cert-18.jpg - Допуск к опасным объектам (док 2)
cert-19.jpg - Лицензия 1
cert-20.jpg - Лицензия 2
cert-21.jpg - Лицензия 3
cert-22.jpg - Лицензия 4
cert-23.jpg - Лицензия 5
cert-24.jpg - Лицензия 6
```
#### ⚠️ ВАЖНО для сертификатов:
**НЕ ГЕНЕРИРУЙТЕ** эти изображения с помощью AI!
Вам нужно:
1. Отсканировать ваши **реальные сертификаты** компании (СРО, лицензии, допуски)
2. Сохранить их как `cert-1.jpg`, `cert-2.jpg`, и т.д.
3. Поместить в папку `media/images/certificates/`
4. Я обновлю код для их использования
**Альтернатива**: Если сертификаты конфиденциальны, можете временно оставить плейсхолдеры.
---
## 📊 ФИНАЛЬНАЯ СТАТИСТИКА
| Категория | Статус | Количество | Процент |
|-----------|--------|------------|---------|
| Hero & Headers | ✅ **Установлено** | 15 | 100% |
| Услуги | ✅ **Установлено** | 7 | 100% |
| О компании | ✅ **Установлено** | 2 | 100% |
| Лаборатории | ✅ **Установлено** | 2 | 100% |
| **Проекты** | ⏳ **Плейсхолдеры** | **93** | 0% |
| **Сертификаты** | ⏳ **Плейсхолдеры** | **24** | 0% |
| **ИТОГО** | | **143** | **19%** ✅ |
---
## 🚀 СЛЕДУЮЩИЕ ДЕЙСТВИЯ
### Для завершения работы осталось:
#### 1. Проекты (93 изображения)
**Выберите один из вариантов:**
**🌟 Вариант A (рекомендуется)**: Создать 6 категорийных изображений
- Создайте папку: `media/images/projects/`
- Сгенерируйте 6 изображений (по промптам выше)
- Назовите: `oil-gas.jpg`, `residential.jpg`, `infrastructure.jpg`, `social.jpg`, `industrial.jpg`, `commercial.jpg`
- Скажите мне → я обновлю код для автоматической привязки по категориям
**🎨 Вариант B**: Сгенерировать 93 уникальных изображения
- Используйте промпты из `IMAGE_GENERATION_LIST.md`
- Назовите: `project-1.jpg` до `project-93.jpg`
- Скажите мне → я обновлю все пути в константах
**⏭️ Вариант C**: Пропустить пока
- Плейсхолдеры будут работать нормально
- Добавите изображения позже
#### 2. Сертификаты (24 изображения)
- **Отсканируйте реальные документы** вашей компании
- Сохраните в: `media/images/certificates/`
- Скажите мне → я обновлю пути
---
## 🎯 ТЕКУЩИЙ РЕЗУЛЬТАТ
**Ваш сайт уже выглядит профессионально!**
Все основные страницы имеют красивые заголовки, услуги отображаются с изображениями, главная страница полностью готова.
Плейсхолдеры для проектов и сертификатов **не критичны** — они показываются корректно и не ломают дизайн.
---
## 💬 Что делать дальше?
Скажите мне:
1. "Создал изображения для проектов" → я подключу их
2. "Оставим проекты с плейсхолдерами" → оставим как есть
3. "Создай скрипт для массового обновления" → я создам автоматизацию
**Готово к запуску сайта!** 🚀

35
components/Benefits.tsx Normal file
View File

@@ -0,0 +1,35 @@
import React from 'react';
import { BENEFITS } from '../constants';
const Benefits: React.FC = () => {
return (
<div className="py-24 bg-white">
<div className="container mx-auto px-6">
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12">
<div className="lg:col-span-4">
<span className="text-sm text-gray-500 uppercase tracking-widest mb-2 block">Выбирая нас</span>
<h2 className="text-4xl font-bold text-gray-900 mb-6">Вы получаете</h2>
<p className="text-gray-500 text-sm">Нас выбирают люди</p>
</div>
<div className="lg:col-span-8 grid grid-cols-1 md:grid-cols-2 gap-x-12 gap-y-16">
{BENEFITS.map((item, index) => (
<div key={index} className="flex flex-col items-start gap-4">
<div className="w-12 h-12 rounded-full bg-brand-orange/20 flex items-center justify-center text-brand-orange">
<item.icon size={24} />
</div>
<p className="text-gray-700 leading-relaxed font-medium">
{item.description}
</p>
</div>
))}
</div>
</div>
</div>
</div>
);
};
export default Benefits;

135
components/Footer.tsx Normal file
View File

@@ -0,0 +1,135 @@
import React from 'react';
import { Send, MapPin, Mail, Phone } from 'lucide-react';
import { Link } from 'react-router-dom';
const Footer: React.FC = () => {
return (
<footer className="bg-[#1a0f0f] text-white py-20 rounded-t-[3rem] mt-auto" id="contacts">
<div className="container mx-auto px-6">
<div className="flex flex-col lg:flex-row gap-20">
{/* Contacts Section with Accent */}
<div className="lg:w-1/2">
<h2 className="text-4xl font-bold mb-8 text-brand-orange">Свяжитесь с нами</h2>
<p className="text-gray-300 text-lg mb-10 max-w-md">
Готовы ответить на ваши вопросы и предложить лучшие решения для вашего проекта
</p>
<div className="space-y-6 max-w-md">
<a
href="tel:83472927370"
className="flex items-start gap-4 p-6 bg-brand-orange/10 border border-brand-orange/30 rounded-2xl hover:bg-brand-orange hover:scale-105 transition-all duration-300 group"
>
<Phone size={28} className="text-brand-orange group-hover:text-white flex-shrink-0" />
<div>
<p className="text-xs text-gray-400 mb-1 group-hover:text-white/80">Телефон</p>
<p className="text-xl font-bold text-white">8 (347) 292 73 70</p>
<p className="text-sm text-gray-400 mt-1 group-hover:text-white/70">Звоните с 9:00 до 18:00</p>
</div>
</a>
<a
href="mailto:gw@geowektor.ru"
className="flex items-start gap-4 p-6 bg-brand-orange/10 border border-brand-orange/30 rounded-2xl hover:bg-brand-orange hover:scale-105 transition-all duration-300 group"
>
<Mail size={28} className="text-brand-orange group-hover:text-white flex-shrink-0" />
<div>
<p className="text-xs text-gray-400 mb-1 group-hover:text-white/80">Email</p>
<p className="text-xl font-bold text-white">gw@geowektor.ru</p>
<p className="text-sm text-gray-400 mt-1 group-hover:text-white/70">Ответим в течение часа</p>
</div>
</a>
<div className="flex items-start gap-4 p-6 bg-brand-orange/10 border border-brand-orange/30 rounded-2xl">
<MapPin size={28} className="text-brand-orange flex-shrink-0" />
<div>
<p className="text-xs text-gray-400 mb-1">Адрес</p>
<p className="text-lg font-bold text-white">450001, РБ, г. Уфа</p>
<p className="text-white/90">ул. Комсомольская 19/1</p>
</div>
</div>
</div>
</div>
{/* Links & Social Section */}
<div className="lg:w-1/2 grid grid-cols-1 md:grid-cols-3 gap-8">
{/* Основная навигация */}
<div>
<h4 className="font-bold mb-6 text-lg">Компания</h4>
<ul className="space-y-3 text-sm text-gray-400">
<li><Link to="/" className="hover:text-brand-orange transition-colors">Главная</Link></li>
<li><Link to="/about" className="hover:text-brand-orange transition-colors">О компании</Link></li>
<li><Link to="/projects" className="hover:text-brand-orange transition-colors">Проекты</Link></li>
<li><Link to="/fleet" className="hover:text-brand-orange transition-colors">Автопарк</Link></li>
<li><Link to="/certificates" className="hover:text-brand-orange transition-colors">Сертификаты</Link></li>
<li><Link to="/contacts" className="hover:text-brand-orange transition-colors">Контакты</Link></li>
</ul>
</div>
{/* Услуги */}
<div>
<h4 className="font-bold mb-6 text-lg">Услуги</h4>
<ul className="space-y-3 text-sm text-gray-400">
<li><Link to="/services" className="hover:text-brand-orange transition-colors">Все услуги</Link></li>
<li><Link to="/services/surveying" className="hover:text-brand-orange transition-colors">Инженерные изыскания</Link></li>
<li><Link to="/services/design" className="hover:text-brand-orange transition-colors">Проектирование</Link></li>
<li><Link to="/services/construction" className="hover:text-brand-orange transition-colors">Строительство</Link></li>
<li><Link to="/services/soil-survey" className="hover:text-brand-orange transition-colors">Обследование грунтов</Link></li>
<li><Link to="/services/building-survey" className="hover:text-brand-orange transition-colors">Обследование зданий</Link></li>
<li><Link to="/services/land-survey" className="hover:text-brand-orange transition-colors">Кадастровые работы</Link></li>
</ul>
</div>
{/* Лаборатории и соцсети */}
<div>
<h4 className="font-bold mb-6 text-lg">Лаборатории</h4>
<ul className="space-y-3 text-sm text-gray-400 mb-8">
<li><Link to="/laboratories/soil" className="hover:text-brand-orange transition-colors">Грунтовая лаборатория</Link></li>
<li><Link to="/laboratories/radiation" className="hover:text-brand-orange transition-colors">Радиационная лаборатория</Link></li>
</ul>
<h4 className="font-bold mb-4 text-lg">Мы в интернете</h4>
<div className="flex gap-4 mb-8">
<a
href="https://t.me/ooo_geo_wektor"
target="_blank"
rel="noopener noreferrer"
className="w-12 h-12 rounded-full bg-brand-orange flex items-center justify-center text-white cursor-pointer hover:bg-white hover:text-brand-orange transition-all transform hover:scale-110"
title="Telegram"
>
<Send size={22} />
</a>
<a
href="https://vk.com/geowektor_ru"
target="_blank"
rel="noopener noreferrer"
className="w-12 h-12 rounded-full bg-brand-orange flex items-center justify-center text-white cursor-pointer hover:bg-white hover:text-brand-orange transition-all transform hover:scale-110"
title="VK"
>
<div className="font-bold text-sm">Vk</div>
</a>
</div>
<div className="space-y-3 text-sm">
<Link
to="/privacy-policy"
className="text-gray-400 hover:text-brand-orange transition-colors block"
>
Политика конфиденциальности
</Link>
</div>
<div className="mt-8 text-xs text-gray-600">
©2025 ООО «ГеоВектор».<br />
Все права защищены.
</div>
</div>
</div>
</div>
</div>
</footer>
);
};
export default Footer;

63
components/Hero.tsx Normal file
View File

@@ -0,0 +1,63 @@
import React from 'react';
import { STATS } from '../constants';
import { Link } from 'react-router-dom';
const Hero: React.FC = () => {
return (
<div className="relative w-full min-h-screen bg-brand-dark text-white flex flex-col">
{/* Background Image Overlay */}
<div className="absolute inset-0 z-0">
<img
src="/media/images/hero/hero-main.png"
alt="Construction Site"
className="w-full h-full object-cover opacity-40"
loading="eager"
/>
<div className="absolute inset-0 bg-gradient-to-r from-brand-dark/90 via-brand-dark/50 to-brand-dark/70 animate-gradient" />
</div>
{/* Hero Content */}
<div className="relative z-10 container mx-auto px-6 flex-grow flex flex-col justify-center py-32 md:py-20">
<div className="max-w-5xl mx-auto text-center mt-10 md:mt-0">
<h1 className="text-4xl md:text-5xl lg:text-7xl font-bold leading-tight mb-8">
Инженерные изыскания,
<br />
<span className="text-brand-orange">проектирование</span> и
<br />
<span className="text-brand-orange">строительство</span>
</h1>
<p className="text-gray-300 text-lg md:text-xl mb-12 max-w-3xl mx-auto leading-relaxed">
ООО «ГеоВектор» профессиональные решения для вашего проекта от изысканий до сдачи объекта.
Современное оборудование, опытные специалисты и соблюдение всех норм и стандартов.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center items-center">
<Link
to="/contacts"
className="inline-flex items-center justify-center bg-brand-orange text-white font-bold py-4 px-8 rounded-xl hover:bg-orange-600 transition-all duration-300 shadow-lg hover:shadow-xl hover:scale-105"
>
Рассчитать стоимость проекта
</Link>
<Link
to="/services"
className="inline-flex items-center justify-center bg-white/10 backdrop-blur-sm text-white font-bold py-4 px-8 rounded-xl hover:bg-white/20 transition-all duration-300 border-2 border-white/30"
>
Наши услуги
</Link>
</div>
</div>
{/* Stats */}
<div className="mt-24 grid grid-cols-1 md:grid-cols-3 gap-8 border-t border-white/10 pt-12 max-w-5xl mx-auto w-full">
{STATS.map((stat, idx) => (
<div key={idx} className="flex flex-col items-center text-center">
<span className="text-4xl md:text-5xl font-bold text-brand-orange mb-2">{stat.value}</span>
<p className="text-gray-400 text-sm md:text-base leading-relaxed">{stat.label}</p>
</div>
))}
</div>
</div>
</div>
);
};
export default Hero;

186
components/Laboratories.tsx Normal file
View File

@@ -0,0 +1,186 @@
import React from 'react';
import { Microscope, Activity, ArrowRight, CheckCircle2, Shield } from 'lucide-react';
import { Link } from 'react-router-dom';
const Laboratories: React.FC = () => {
return (
<section className="py-20 bg-gradient-to-b from-white to-gray-50">
<div className="container mx-auto px-6">
<div className="text-center mb-16">
<div className="inline-flex items-center justify-center w-16 h-16 bg-brand-orange/10 rounded-full mb-6">
<Microscope className="text-brand-orange" size={32} />
</div>
<h2 className="text-4xl md:text-5xl font-bold text-gray-900 mb-4">
Наши лаборатории
</h2>
<p className="text-gray-600 text-lg max-w-2xl mx-auto">
Современное оборудование и квалифицированные специалисты для проведения
комплексных исследований
</p>
</div>
<div className="max-w-7xl mx-auto grid md:grid-cols-2 gap-8">
{/* Грунтовая лаборатория */}
<div className="group bg-white rounded-3xl overflow-hidden shadow-xl hover:shadow-2xl transition-all duration-300 border-2 border-transparent hover:border-brand-orange">
{/* Изображение с наложением */}
<div className="relative h-64 overflow-hidden">
<img
src="/media/images/services/soil-survey.png"
alt="Грунтовая лаборатория"
className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-500"
loading="lazy"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/70 via-black/30 to-transparent"></div>
{/* Иконка */}
<div className="absolute top-6 left-6">
<div className="w-16 h-16 bg-white/20 backdrop-blur-md rounded-xl flex items-center justify-center border-2 border-white/30">
<Microscope className="text-white" size={32} />
</div>
</div>
{/* Заголовок на изображении */}
<div className="absolute bottom-6 left-6 right-6">
<h3 className="text-2xl font-bold text-white mb-2">
Грунтовая лаборатория
</h3>
<p className="text-white/90 text-sm">
Исследования физических, механических и химических свойств
</p>
</div>
</div>
{/* Контент карточки */}
<div className="p-8">
<div className="space-y-4 mb-8">
<div className="flex items-start gap-3">
<CheckCircle2 className="text-brand-orange flex-shrink-0 mt-1" size={20} />
<div>
<p className="text-gray-700 font-medium">Физические свойства грунтов</p>
<p className="text-sm text-gray-500">Влажность, плотность, гранулометрический состав</p>
</div>
</div>
<div className="flex items-start gap-3">
<CheckCircle2 className="text-brand-orange flex-shrink-0 mt-1" size={20} />
<div>
<p className="text-gray-700 font-medium">Механические характеристики</p>
<p className="text-sm text-gray-500">Прочность, деформируемость, сжимаемость</p>
</div>
</div>
<div className="flex items-start gap-3">
<CheckCircle2 className="text-brand-orange flex-shrink-0 mt-1" size={20} />
<div>
<p className="text-gray-700 font-medium">Химический анализ</p>
<p className="text-sm text-gray-500">Агрессивность грунтов, анализ воды</p>
</div>
</div>
</div>
{/* Кнопка */}
<Link
to="/laboratories/soil"
className="flex items-center justify-center gap-2 w-full py-4 bg-gradient-to-r from-brand-orange to-orange-600 text-white font-bold rounded-xl hover:from-orange-600 hover:to-brand-orange transition-all duration-300 group/btn"
>
Подробнее о лаборатории
<ArrowRight className="group-hover/btn:translate-x-1 transition-transform" size={20} />
</Link>
</div>
</div>
{/* Радиационная лаборатория */}
<div className="group bg-white rounded-3xl overflow-hidden shadow-xl hover:shadow-2xl transition-all duration-300 border-2 border-transparent hover:border-brand-orange">
{/* Изображение с наложением */}
<div className="relative h-64 overflow-hidden">
<img
src="/media/images/services/engineering-surveys.png"
alt="Радиационная лаборатория"
className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-500"
loading="lazy"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/70 via-black/30 to-transparent"></div>
{/* Иконка */}
<div className="absolute top-6 left-6">
<div className="w-16 h-16 bg-white/20 backdrop-blur-md rounded-xl flex items-center justify-center border-2 border-white/30">
<Activity className="text-white" size={32} />
</div>
</div>
{/* Заголовок на изображении */}
<div className="absolute bottom-6 left-6 right-6">
<h3 className="text-2xl font-bold text-white mb-2">
Радиационная лаборатория
</h3>
<p className="text-white/90 text-sm">
Профессиональные исследования радиационной безопасности
</p>
</div>
</div>
{/* Контент карточки */}
<div className="p-8">
<div className="space-y-4 mb-8">
<div className="flex items-start gap-3">
<Shield className="text-brand-orange flex-shrink-0 mt-1" size={20} />
<div>
<p className="text-gray-700 font-medium">Радиационный контроль</p>
<p className="text-sm text-gray-500">Измерение уровня радона и гамма-излучения</p>
</div>
</div>
<div className="flex items-start gap-3">
<Shield className="text-brand-orange flex-shrink-0 mt-1" size={20} />
<div>
<p className="text-gray-700 font-medium">Аккредитованная лаборатория</p>
<p className="text-sm text-gray-500">Техническая компетентность и независимость</p>
</div>
</div>
<div className="flex items-start gap-3">
<Shield className="text-brand-orange flex-shrink-0 mt-1" size={20} />
<div>
<p className="text-gray-700 font-medium">Современное оборудование</p>
<p className="text-sm text-gray-500">КАМЕРА-01, ДКГ-02У, ДРБП-03</p>
</div>
</div>
</div>
{/* Кнопка */}
<Link
to="/laboratories/radiation"
className="flex items-center justify-center gap-2 w-full py-4 bg-gradient-to-r from-brand-orange to-orange-600 text-white font-bold rounded-xl hover:from-orange-600 hover:to-brand-orange transition-all duration-300 group/btn"
>
Подробнее о лаборатории
<ArrowRight className="group-hover/btn:translate-x-1 transition-transform" size={20} />
</Link>
</div>
</div>
</div>
{/* Дополнительная информация */}
<div className="mt-16 max-w-4xl mx-auto">
<div className="bg-gradient-to-br from-gray-900 to-gray-800 text-white rounded-2xl p-8 md:p-12 text-center">
<h3 className="text-2xl md:text-3xl font-bold mb-4">
Нужна консультация по лабораторным исследованиям?
</h3>
<p className="text-gray-300 mb-6 max-w-2xl mx-auto">
Наши специалисты помогут подобрать оптимальный комплекс исследований для вашего проекта
</p>
<Link
to="/contacts"
className="inline-flex items-center gap-2 px-8 py-4 bg-brand-orange text-white font-bold rounded-xl hover:bg-orange-600 transition-colors"
>
Связаться с нами
<ArrowRight size={20} />
</Link>
</div>
</div>
</div>
</section>
);
};
export default Laboratories;

25
components/Loading.tsx Normal file
View File

@@ -0,0 +1,25 @@
import React from 'react';
const Loading: React.FC = () => {
return (
<div className="fixed inset-0 bg-brand-dark flex items-center justify-center z-50">
<div className="text-center">
<img
src="/media/geo-logo.webp"
alt="ГеоВектор"
className="w-24 h-24 mx-auto mb-6 animate-pulse"
/>
<div className="flex items-center justify-center gap-2">
<div className="w-3 h-3 bg-brand-orange rounded-full animate-bounce"></div>
<div className="w-3 h-3 bg-brand-orange rounded-full animate-bounce" style={{ animationDelay: '0.1s' }}></div>
<div className="w-3 h-3 bg-brand-orange rounded-full animate-bounce" style={{ animationDelay: '0.2s' }}></div>
</div>
<p className="text-gray-400 mt-4 text-sm">Загрузка...</p>
</div>
</div>
);
};
export default Loading;

414
components/Navbar.tsx Normal file
View File

@@ -0,0 +1,414 @@
import React, { useState, useEffect } from 'react';
import { Phone, Menu, X, ChevronDown } from 'lucide-react';
import { Link, useLocation } from 'react-router-dom';
import { NAV_LINKS } from '../constants';
interface NavbarProps {
transparent?: boolean;
}
const Navbar: React.FC<NavbarProps> = ({ transparent = false }) => {
const [isScrolled, setIsScrolled] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [isMobileServicesMenuOpen, setIsMobileServicesMenuOpen] = useState(false);
const [isMobileLabMenuOpen, setIsMobileLabMenuOpen] = useState(false);
const [imgError, setImgError] = useState(false);
const location = useLocation();
useEffect(() => {
const handleScroll = () => {
setIsScrolled(window.scrollY > 50);
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
const isHome = location.pathname === '/';
// Use transparent background only on Home and when not scrolled, if requested
const isTransparent = transparent && isHome && !isScrolled;
return (
<nav
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
isTransparent ? 'bg-transparent py-6' : 'bg-brand-dark/95 backdrop-blur-md py-4 shadow-lg'
}`}
>
<div className="container mx-auto px-6 flex items-center justify-between text-white">
{/* Logo */}
<Link to="/" className="flex items-center gap-2 group">
{!imgError ? (
<img
src="/media/geo-logo.webp"
alt="ГеоВектор"
className="h-[64px] w-auto object-contain"
onError={() => setImgError(true)}
/>
) : (
<span className="text-xl font-bold tracking-tighter">
ГЕО<span className="text-brand-orange">ВЕКТОР</span>
</span>
)}
</Link>
{/* Desktop Menu */}
<ul className="hidden md:flex gap-8 text-sm font-medium items-center">
{/* Главная */}
<li>
<Link
to="/"
className={`transition-colors hover:text-brand-orange ${
location.pathname === '/' ? 'text-brand-orange' : 'text-gray-300'
}`}
>
Главная
</Link>
</li>
{/* О компании */}
<li>
<Link
to="/about"
className={`transition-colors hover:text-brand-orange ${
location.pathname === '/about' ? 'text-brand-orange' : 'text-gray-300'
}`}
>
О компании
</Link>
</li>
{/* Услуги с выпадающим меню */}
<li className="relative group">
<button
className={`flex items-center gap-1 transition-colors hover:text-brand-orange ${
location.pathname.startsWith('/services') ? 'text-brand-orange' : 'text-gray-300'
}`}
>
Услуги
<ChevronDown size={16} className={`transition-transform group-hover:rotate-180`} />
</button>
{/* Выпадающее меню */}
<div className="absolute top-full left-0 pt-2 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200">
<div className="w-72 bg-brand-dark border border-gray-700 rounded-lg shadow-xl overflow-hidden">
<Link
to="/services"
className="block px-6 py-3 text-gray-300 hover:bg-brand-orange hover:text-white transition-colors font-semibold border-b border-gray-700"
>
Все услуги
</Link>
<Link
to="/services/surveying"
className="block px-6 py-3 text-gray-300 hover:bg-brand-orange hover:text-white transition-colors"
>
Инженерные изыскания
</Link>
<Link
to="/services/design"
className="block px-6 py-3 text-gray-300 hover:bg-brand-orange hover:text-white transition-colors"
>
Проектирование
</Link>
<Link
to="/services/construction"
className="block px-6 py-3 text-gray-300 hover:bg-brand-orange hover:text-white transition-colors"
>
Строительство
</Link>
<Link
to="/services/soil-survey"
className="block px-6 py-3 text-gray-300 hover:bg-brand-orange hover:text-white transition-colors"
>
Обследование грунтов
</Link>
<Link
to="/services/building-survey"
className="block px-6 py-3 text-gray-300 hover:bg-brand-orange hover:text-white transition-colors"
>
Обследование здания
</Link>
<Link
to="/services/land-survey"
className="block px-6 py-3 text-gray-300 hover:bg-brand-orange hover:text-white transition-colors"
>
Кадастровые работы
</Link>
<Link
to="/services/technical-tasks"
className="block px-6 py-3 text-gray-300 hover:bg-brand-orange hover:text-white transition-colors border-t border-gray-700"
>
Образцы технических заданий
</Link>
</div>
</div>
</li>
{/* Проекты */}
<li>
<Link
to="/projects"
className={`transition-colors hover:text-brand-orange ${
location.pathname === '/projects' ? 'text-brand-orange' : 'text-gray-300'
}`}
>
Проекты
</Link>
</li>
{/* Автопарк */}
<li>
<Link
to="/fleet"
className={`transition-colors hover:text-brand-orange ${
location.pathname === '/fleet' ? 'text-brand-orange' : 'text-gray-300'
}`}
>
Автопарк
</Link>
</li>
{/* Сертификаты */}
<li>
<Link
to="/certificates"
className={`transition-colors hover:text-brand-orange ${
location.pathname === '/certificates' ? 'text-brand-orange' : 'text-gray-300'
}`}
>
Сертификаты
</Link>
</li>
{/* Лаборатории с выпадающим меню */}
<li className="relative group">
<button
className={`flex items-center gap-1 transition-colors hover:text-brand-orange ${
location.pathname.startsWith('/laboratories') ? 'text-brand-orange' : 'text-gray-300'
}`}
>
Лаборатории
<ChevronDown size={16} className={`transition-transform group-hover:rotate-180`} />
</button>
{/* Выпадающее меню */}
<div className="absolute top-full left-0 pt-2 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200">
<div className="w-64 bg-brand-dark border border-gray-700 rounded-lg shadow-xl overflow-hidden">
<Link
to="/laboratories/soil"
className="block px-6 py-3 text-gray-300 hover:bg-brand-orange hover:text-white transition-colors"
>
Грунтовая лаборатория
</Link>
<Link
to="/laboratories/radiation"
className="block px-6 py-3 text-gray-300 hover:bg-brand-orange hover:text-white transition-colors"
>
Радиационная лаборатория
</Link>
</div>
</div>
</li>
{/* Контакты */}
<li>
<Link
to="/contacts"
className={`transition-colors hover:text-brand-orange ${
location.pathname === '/contacts' ? 'text-brand-orange' : 'text-gray-300'
}`}
>
Контакты
</Link>
</li>
</ul>
{/* CTA & Mobile Toggle */}
<div className="flex items-center gap-4">
<Link to="/contacts" className="hidden md:flex items-center gap-2 text-sm font-medium hover:text-brand-orange transition-colors">
<Phone className="w-4 h-4 text-brand-orange" />
<span>Связаться</span>
</Link>
<button
className="md:hidden text-white"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
>
{isMobileMenuOpen ? <X /> : <Menu />}
</button>
</div>
</div>
{/* Mobile Menu */}
{isMobileMenuOpen && (
<div className="absolute top-full left-0 w-full bg-brand-dark border-t border-gray-800 p-6 flex flex-col gap-6 md:hidden shadow-xl">
{/* Главная */}
<Link
to="/"
className="text-lg font-medium text-gray-300 hover:text-brand-orange"
onClick={() => setIsMobileMenuOpen(false)}
>
Главная
</Link>
{/* О компании */}
<Link
to="/about"
className="text-lg font-medium text-gray-300 hover:text-brand-orange"
onClick={() => setIsMobileMenuOpen(false)}
>
О компании
</Link>
{/* Услуги в мобильном меню */}
<div>
<button
className="flex items-center justify-between w-full text-lg font-medium text-gray-300 hover:text-brand-orange"
onClick={() => setIsMobileServicesMenuOpen(!isMobileServicesMenuOpen)}
>
Услуги
<ChevronDown size={20} className={`transition-transform ${isMobileServicesMenuOpen ? 'rotate-180' : ''}`} />
</button>
{isMobileServicesMenuOpen && (
<div className="ml-4 mt-3 flex flex-col gap-3">
<Link
to="/services"
className="text-gray-400 hover:text-brand-orange font-semibold"
onClick={() => setIsMobileMenuOpen(false)}
>
Все услуги
</Link>
<Link
to="/services/surveying"
className="text-gray-400 hover:text-brand-orange"
onClick={() => setIsMobileMenuOpen(false)}
>
Инженерные изыскания
</Link>
<Link
to="/services/design"
className="text-gray-400 hover:text-brand-orange"
onClick={() => setIsMobileMenuOpen(false)}
>
Проектирование
</Link>
<Link
to="/services/construction"
className="text-gray-400 hover:text-brand-orange"
onClick={() => setIsMobileMenuOpen(false)}
>
Строительство
</Link>
<Link
to="/services/soil-survey"
className="text-gray-400 hover:text-brand-orange"
onClick={() => setIsMobileMenuOpen(false)}
>
Обследование грунтов
</Link>
<Link
to="/services/building-survey"
className="text-gray-400 hover:text-brand-orange"
onClick={() => setIsMobileMenuOpen(false)}
>
Обследование здания
</Link>
<Link
to="/services/land-survey"
className="text-gray-400 hover:text-brand-orange"
onClick={() => setIsMobileMenuOpen(false)}
>
Кадастровые работы
</Link>
<Link
to="/services/technical-tasks"
className="text-gray-400 hover:text-brand-orange"
onClick={() => setIsMobileMenuOpen(false)}
>
Образцы ТЗ
</Link>
</div>
)}
</div>
{/* Проекты */}
<Link
to="/projects"
className="text-lg font-medium text-gray-300 hover:text-brand-orange"
onClick={() => setIsMobileMenuOpen(false)}
>
Проекты
</Link>
{/* Автопарк */}
<Link
to="/fleet"
className="text-lg font-medium text-gray-300 hover:text-brand-orange"
onClick={() => setIsMobileMenuOpen(false)}
>
Автопарк
</Link>
{/* Сертификаты */}
<Link
to="/certificates"
className="text-lg font-medium text-gray-300 hover:text-brand-orange"
onClick={() => setIsMobileMenuOpen(false)}
>
Сертификаты
</Link>
{/* Лаборатории в мобильном меню */}
<div>
<button
className="flex items-center justify-between w-full text-lg font-medium text-gray-300 hover:text-brand-orange"
onClick={() => setIsMobileLabMenuOpen(!isMobileLabMenuOpen)}
>
Лаборатории
<ChevronDown size={20} className={`transition-transform ${isMobileLabMenuOpen ? 'rotate-180' : ''}`} />
</button>
{isMobileLabMenuOpen && (
<div className="ml-4 mt-3 flex flex-col gap-3">
<Link
to="/laboratories/soil"
className="text-gray-400 hover:text-brand-orange"
onClick={() => setIsMobileMenuOpen(false)}
>
Грунтовая лаборатория
</Link>
<Link
to="/laboratories/radiation"
className="text-gray-400 hover:text-brand-orange"
onClick={() => setIsMobileMenuOpen(false)}
>
Радиационная лаборатория
</Link>
</div>
)}
</div>
{/* Контакты */}
<Link
to="/contacts"
className="text-lg font-medium text-gray-300 hover:text-brand-orange"
onClick={() => setIsMobileMenuOpen(false)}
>
Контакты
</Link>
<Link
to="/contacts"
className="flex items-center gap-2 text-brand-orange font-bold mt-4"
onClick={() => setIsMobileMenuOpen(false)}
>
<Phone className="w-5 h-5" /> Связаться
</Link>
</div>
)}
</nav>
);
};
export default Navbar;

37
components/PageHeader.tsx Normal file
View File

@@ -0,0 +1,37 @@
import React from 'react';
interface PageHeaderProps {
title: string;
description?: string;
image?: string;
}
const PageHeader: React.FC<PageHeaderProps> = ({
title,
description,
image = "/media/images/headers/header-about.png"
}) => {
return (
<div className="relative w-full h-[400px] md:h-[500px] bg-brand-dark text-white flex flex-col justify-center items-center text-center overflow-hidden">
<div className="absolute inset-0 z-0">
<img
src={image}
alt={title}
className="w-full h-full object-cover opacity-30"
/>
<div className="absolute inset-0 bg-gradient-to-b from-brand-dark/80 to-brand-dark/40" />
</div>
<div className="relative z-10 container mx-auto px-6 mt-16">
<h1 className="text-4xl md:text-5xl lg:text-6xl font-bold mb-6">{title}</h1>
{description && (
<p className="text-gray-300 text-lg max-w-2xl mx-auto leading-relaxed">
{description}
</p>
)}
</div>
</div>
);
};
export default PageHeader;

40
components/Process.tsx Normal file
View File

@@ -0,0 +1,40 @@
import React from 'react';
import { STEPS } from '../constants';
const Process: React.FC = () => {
return (
<div className="py-20 bg-brand-light">
<div className="container mx-auto px-6">
<h2 className="text-4xl font-bold text-gray-900 mb-16 text-center">Как мы работаем</h2>
<div className="relative max-w-6xl mx-auto">
{/* Линия связи между шагами (только на больших экранах) */}
<div className="hidden lg:block absolute top-9 left-0 right-0 h-1 bg-gradient-to-r from-brand-orange via-brand-orange/50 to-brand-orange" style={{ zIndex: 0 }} />
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 relative" style={{ zIndex: 1 }}>
{STEPS.map((step, idx) => (
<div key={idx} className="relative">
{/* Номер шага */}
<div className="absolute -top-4 -left-4 w-10 h-10 bg-brand-orange text-white rounded-full flex items-center justify-center font-bold text-lg shadow-lg z-10 border-4 border-brand-light">
{idx + 1}
</div>
{/* Карточка шага */}
<div className="bg-white rounded-2xl p-6 shadow-md hover:shadow-xl transition-all duration-300 hover:scale-105 h-full border-2 border-transparent hover:border-brand-orange">
<div className="w-14 h-14 rounded-full bg-brand-orange/20 flex items-center justify-center text-brand-orange mb-4">
<step.icon size={28} />
</div>
<p className="text-gray-700 leading-relaxed">
{step.description}
</p>
</div>
</div>
))}
</div>
</div>
</div>
</div>
);
};
export default Process;

103
components/Projects.tsx Normal file
View File

@@ -0,0 +1,103 @@
import React, { useState } from 'react';
import { groupProjectsByCategory } from '../constants';
import { MapPin, ChevronDown } from 'lucide-react';
import { Link } from 'react-router-dom';
const Projects: React.FC = () => {
const categories = groupProjectsByCategory().slice(0, 3); // Показываем только 3 категории
const [openCategories, setOpenCategories] = useState<{ [key: string]: boolean }>({
[categories[0]?.name]: true // Открываем первую категорию по умолчанию
});
const toggleCategory = (categoryName: string) => {
setOpenCategories(prev => ({
...prev,
[categoryName]: !prev[categoryName]
}));
};
return (
<div className="py-24 bg-white" id="projects">
<div className="container mx-auto px-6">
<div className="flex flex-col md:flex-row justify-between items-start md:items-end mb-16 gap-8">
<h2 className="text-4xl font-bold text-gray-900 max-w-xs leading-tight">
Наши недавние проекты
</h2>
<p className="text-gray-600 max-w-md text-sm leading-relaxed">
Наша команда всегда ответственно относится к проектам, которые вы нам доверили.
Спасибо, что вы рядом.
</p>
</div>
<div className="space-y-4 mb-8">
{categories.map((category) => (
<div key={category.name} className="border border-gray-200 rounded-xl overflow-hidden">
{/* Заголовок категории */}
<button
onClick={() => toggleCategory(category.name)}
className="w-full flex items-center justify-between p-6 bg-gray-50 hover:bg-gray-100 transition-colors"
>
<div className="flex items-center gap-4">
<div className="flex-shrink-0 w-12 h-12 bg-brand-orange text-white rounded-lg flex items-center justify-center font-bold text-lg">
{category.projects.length}
</div>
<h3 className="text-xl font-bold text-gray-900">{category.name}</h3>
</div>
<ChevronDown
size={24}
className={`text-brand-orange transition-transform duration-300 ${
openCategories[category.name] ? 'rotate-180' : ''
}`}
/>
</button>
{/* Список проектов (показываем только первые 3) */}
<div
className={`transition-all duration-300 ${
openCategories[category.name]
? 'max-h-[2000px] opacity-100'
: 'max-h-0 opacity-0 overflow-hidden'
}`}
>
<div className="p-4 space-y-3 bg-white">
{category.projects.slice(0, 3).map((project, index) => (
<div
key={project.id}
className="group cursor-pointer bg-gray-50 hover:bg-gray-100 rounded-lg p-5 transition-all duration-300 border border-gray-200 hover:border-brand-orange"
>
<div className="flex items-start gap-4">
<div className="flex-shrink-0 w-10 h-10 bg-white border-2 border-brand-orange text-brand-orange rounded-lg flex items-center justify-center font-bold text-sm">
{index + 1}
</div>
<div className="flex-1">
<h4 className="text-base font-bold text-gray-900 mb-2 group-hover:text-brand-orange transition-colors">
{project.title}
</h4>
<div className="flex items-start gap-2 text-gray-600 text-sm">
<MapPin size={14} className="mt-1 flex-shrink-0 text-brand-orange" />
<span className="leading-relaxed line-clamp-2">{project.description}</span>
</div>
</div>
</div>
</div>
))}
</div>
</div>
</div>
))}
</div>
<div className="text-center">
<Link
to="/projects"
className="inline-block px-8 py-3 bg-brand-orange text-white font-bold rounded-lg hover:bg-orange-600 transition-colors"
>
Смотреть все проекты
</Link>
</div>
</div>
</div>
);
};
export default Projects;

View File

@@ -0,0 +1,38 @@
import React, { useState, useEffect } from 'react';
import { ArrowUp } from 'lucide-react';
const ScrollToTop: React.FC = () => {
const [visible, setVisible] = useState(false);
useEffect(() => {
const onScroll = () => {
setVisible(window.scrollY > 300);
};
window.addEventListener('scroll', onScroll);
return () => window.removeEventListener('scroll', onScroll);
}, []);
const scrollToTop = () => {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
};
if (!visible) return null;
return (
<button
onClick={scrollToTop}
className="fixed bottom-8 right-8 w-14 h-14 bg-brand-orange rounded-full shadow-2xl hover:bg-orange-600 hover:scale-110 transition-all z-40 flex items-center justify-center group"
aria-label="Наверх"
>
<ArrowUp className="text-white group-hover:translate-y-[-2px] transition-transform" size={24} />
</button>
);
};
export default ScrollToTop;

83
components/Services.tsx Normal file
View File

@@ -0,0 +1,83 @@
import React from 'react';
import { ArrowRight } from 'lucide-react';
import { Link } from 'react-router-dom';
import { SERVICES } from '../constants';
const Services: React.FC = () => {
// Exclude Technical Tasks and show first 3 actual services
const actualServices = SERVICES.filter(service => service.title !== 'Технические задания');
const displayedServices = actualServices.slice(0, 3);
// Helper function to get service detail page URL
const getServiceUrl = (title: string) => {
const urlMap: { [key: string]: string } = {
'Инженерные изыскания': '/services/surveying',
'Проектирование': '/services/design',
'Строительство': '/services/construction',
'Обследование грунтов': '/services/soil-survey',
'Обследование здания': '/services/building-survey',
'Землестроительный и Кадастровые работы': '/services/land-survey'
};
return urlMap[title] || null;
};
return (
<div className="py-20 bg-gray-50" id="services">
<div className="container mx-auto px-6">
<div className="flex justify-between items-end mb-12">
<h2 className="text-4xl font-bold text-gray-900">Услуги</h2>
<Link to="/services" className="flex items-center gap-2 text-sm font-medium hover:text-brand-orange transition-colors">
Показать все <ArrowRight size={16} />
</Link>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{displayedServices.map((service, idx) => {
const detailUrl = getServiceUrl(service.title);
return (
<div
key={idx}
className="group relative h-[500px] rounded-2xl overflow-hidden cursor-pointer shadow-lg"
>
<img
src={service.image}
alt={service.title}
className="absolute inset-0 w-full h-full object-cover transition-transform duration-700 group-hover:scale-110"
loading="lazy"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/90 via-black/40 to-transparent" />
<div className="absolute bottom-0 left-0 p-8 w-full">
<h3 className="text-2xl font-bold text-white mb-3">{service.title}</h3>
<p className="text-gray-300 text-sm mb-6 line-clamp-3 opacity-90">
{service.description}
</p>
<div className="flex flex-col gap-3">
{detailUrl && (
<Link
to={detailUrl}
className="inline-flex items-center justify-center gap-2 bg-brand-orange text-white font-bold px-5 py-2.5 rounded-lg hover:bg-orange-600 transition-colors"
>
Подробнее <ArrowRight size={18} />
</Link>
)}
<Link
to="/contacts"
className="flex items-center gap-2 text-brand-orange text-sm font-medium group-hover:gap-4 transition-all"
>
Рассчитать стоимость <ArrowRight size={16} />
</Link>
</div>
</div>
</div>
);
})}
</div>
</div>
</div>
);
};
export default Services;

270
constants.ts Normal file
View File

@@ -0,0 +1,270 @@
import { ShieldCheck, Users, HardHat, FileText, Phone, MessageSquare, Briefcase, DraftingCompass, Map, Zap, Calculator, Microscope, Home, Layers } from 'lucide-react';
import { BenefitItem, ProjectItem, ServiceItem, StatItem, StepItem, ProjectCategory } from './types';
export const NAV_LINKS = [
{ label: 'Главная', href: '/' },
{ label: 'О компании', href: '/about' },
{ label: 'Услуги', href: '/services' },
{ label: 'Проекты', href: '/projects' },
{ label: 'Автопарк', href: '/fleet' },
{ label: 'Сертификаты', href: '/certificates' },
{ label: 'Контакты', href: '/contacts' },
];
export const STATS: StatItem[] = [
{ value: '10+', label: '> 10-ти лет помогаем организациям в проектах любой сложности' },
{ value: '20+', label: '> 20-ти крупных компаний, которые нам доверяют' },
{ value: '30+', label: '> 30-ти успешно реализованных проектов за 3 года' },
];
export const BENEFITS: BenefitItem[] = [
{
icon: ShieldCheck,
title: 'Надежность',
description: 'Надежную компанию, которая входит в ТОП-3 по Республике Башкортостан'
},
{
icon: Users,
title: 'Опыт',
description: 'Лучших инженеров с 10-ти летним и более опытом работы'
},
{
icon: Phone,
title: 'Поддержка',
description: 'Связь и поддержку на всех этапах 24/7 с нашими специалистами'
},
{
icon: FileText,
title: 'Условия',
description: 'Индивидуальные предложения и условия сотрудничества'
},
];
export const SERVICES: ServiceItem[] = [
{
title: 'Технические задания',
description: 'Разработка и согласование грамотных технических заданий на проектирование, изыскания и строительство. Помощь в формулировании требований к объекту.',
image: '/media/images/services/technical-assignments.png'
},
{
title: 'Инженерные изыскания',
description: 'Комплексные исследования условий площадки строительства: инженерно-геодезические, геологические, гидрометеорологические и экологические изыскания.',
image: '/media/images/services/engineering-surveys.png'
},
{
title: 'Проектирование',
description: 'Разработка проектной и рабочей документации (ПД и РД) для объектов гражданского и промышленного назначения. Архитектурные и конструктивные решения.',
image: '/media/images/services/design.png'
},
{
title: 'Строительство',
description: 'Выполнение полного цикла строительно-монтажных работ. Возведение зданий, сооружений, ангаров, реконструкция и капитальный ремонт.',
image: '/media/images/services/construction.png'
},
{
title: 'Обследование грунтов',
description: 'Лабораторные и полевые испытания грунтов. Определение физико-механических свойств для расчета фундаментов и оснований.',
image: '/media/images/services/soil-survey.png'
},
{
title: 'Обследование здания',
description: 'Техническое обследование зданий и сооружений. Оценка состояния несущих конструкций, выявление дефектов и разработка рекомендаций по усилению.',
image: '/media/images/services/building-inspection.png'
},
{
title: 'Землестроительный и Кадастровые работы',
description: 'Межевание земельных участков, составление технических планов, актов обследования. Постановка недвижимости на государственный кадастровый учет.',
image: '/media/images/services/cadastral-works.png'
}
];
export const PROJECTS: ProjectItem[] = [
{ id: 1, title: 'ОАО «Газпромнефть-ОНПЗ»', description: '«Модернизация установки 19/3 ОАО «Газпромнефть-ОНПЗ» г. Омск»', image: 'https://placehold.co/600x400/94a3b8/white', category: 'Нефтегазовая промышленность' },
{ id: 2, title: 'ООО «Петон»', description: '«Л-24/9.Техническое перевооружение. Рекуперация тепла ГО ДТ (проектная и рабочая документация)» на территории ОАО «Газпромнефть-ОНПЗ».', image: 'https://placehold.co/600x400/94a3b8/white', category: 'Нефтегазовая промышленность' },
{ id: 3, title: 'ООО «ПроектТехнолоджи»', description: '«Капитальный ремонт системы отопления АБК (литер Ж) базы Южного эксплуатационного района по ул. Б. Гражданская, 47 Советского района г. Уфы и капитальный ремонт подпорной стенки с заменой ограждения на Центральной базе по адресу г. Уфа ул. Пархоменко, 157»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 4, title: 'ООО «ФРЕОН»', description: '«Строительство зоновой ВОЛС на участке: Уфа-отводы-2»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 5, title: 'ОАО «Гипротрубопровод»', description: '«Реконструкция производственной базы г. Омск»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 6, title: 'ООО «ИНЦЭБ»', description: '«Строительство ПС Кустаревская с трансформаторами 2*40 МВА (г.Уфа) (ПО УГЭС ООО «Башкирэнерго»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 7, title: 'ОАО «Уралтранснефтепродукт»', description: '«Переход МН ТОН-2(осн.нитка), через малый водоток р.Чумляк, 631.4 км. ДУ-700, ЛПДС «Медведское», Курганское НУ. Реконструкция»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 8, title: 'ООО «Лукойл-Уралнефтепродукт»', description: '«Реконструкция АЗС №02018 РБ. г. Туймазы, ул. С. Юлаева д.2»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 9, title: 'ООО ХК «Новолекс»', description: '«Лента», расположенный по адресу: г. Уфа, ул. Сипайловская»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 10, title: 'ООО «СУ-1 ОАО «Госстрой»', description: '«Ресторан быстрого обслуживания «KFC» на пересечении улиц Маршала Жукова и Академика Королева в Октябрьском районе ГО г.Уфа»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 11, title: 'ОАО «Юго - Запад транснефтепродукт»', description: '«Обустройство КЗ СОД (камера запуска) на ЛПДС «Журавлинская» МНПП «Уфа- Западное направление», Ду500»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 12, title: 'ООО «ГЕРАЛ»', description: '«Многоквартирный жилой дом в квартале ограниченном улицами Кузнецовский затон, Пугачева, рекой Уфа в Кировском районе ГО г. Уфа»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 13, title: 'ООО «Управление капитального строительства «Монолитстрой»', description: '«Группа многоэтажных жилых домов со встроено-пристроенными помещениями предприятий обслуживания населения, полуподземных автостоянок, здания ЖЭУ с административными помещениями и подземной автостоянкой, здания прачечной и химчистки с административными помещениями и подземной автостоянкой по ул. Дагестанской (микрорайон №9)в Демском районе городского округа г. Уфа, Республики Башкортостан, Жилой дом №13»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 14, title: 'ООО «ИНЦЭБ»', description: '«Строительство Бугульчанской солнечной электростанции»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 15, title: 'ООО «ИНЦЭБ»', description: '«Физкультурно-оздоровительный комплекс БРГИ № 1 имени Рами Гарипова в г. Уфа»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 16, title: 'НГДУ «Уфанефть» (ЦДНГ 4-7 скв., ЦДНГ 5-8 скв., ЦДНГ3- Блохинское)»', description: '«Организация индивидуалных замеров на добывающих скважинах, не охваченных замерными устройствами»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 17, title: 'ОАО «Гипровостокнефть»', description: '«ДНС с УПСВ «Графская» ООО Бугурусланнефть»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 18, title: 'ОАО Оренбургнефть, НГДУ «Сорочинскнефть»', description: '«Обустройство дополнительных скважин №№ 5112, 5216, 5217, 5218, 5219, 5220, 5222, 5225, 5227, 5229, 5230, 5231, 5233, 5234, 5235 Вахитовское месторождение»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 19, title: 'ООО «Башкирский птицеводческий комплекс имени М. Гафури»', description: '«Архитектурного объекта гражданского назначения «Административно-хозяйственного корпуса»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 20, title: 'ЗАО «ВолгоПромСтройМонтаж»', description: '«Строительство базовой станции БС 02-1298GU, цифровой сотовой системы связи стандарта GSM-900/1800/2100 в ОАО «МТС», Республике Башкортостан, Уфимский р-он., н/п Алкино. «Строительство базовой станции БС 02-1560GU, цифровой сотовой системы связи стандарта GSM-900/1800/2100 в ОАО «МТС», Республике Башкортостан, г. Ишимбай, п. Нефтяник. «Строительство базовой станции БС 02-1566G, цифровой сотовой системы связи стандарта GSM-900/1800/2100 в ОАО «МТС», Республике Башкортостан, Баймакский р-он., свх. Зилаирский «Строительство базовой станции БС 02-1567GU, цифровой сотовой системы связи стандарта GSM-900/1800/2100 в ОАО «МТС», Республике Башкортостан, Учалинский р-он., п. Комсомольский»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 21, title: 'ООО «СОЗАиТ»', description: '«Строительство производственного цеха в с. Серафимовский, в Туймазинском районе Республики Башкортостан»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 22, title: 'ЗАО «ВолгоПромСтройМонтаж»', description: '«Строительство базовой станции БС 02-1730, цифровой сотовой системы связи стандарта GSM-900/1800/2100 в ОАО «МТС», Республике Башкортостан, г.Октябрьский, ул. Партизанская»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 23, title: 'ОАО «Сибнефтепровод»', description: '«РВС- 20000 м3 №6 ЛПДС «Западный Сургут» Сургутское УМН. Реконструкция»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 24, title: 'ОАО «Институт Нефтепродуктпроект»', description: '«Обустройство КЗ СОД (камера запуска) на ЛПДС «Пенза» МНПП «Уфа - Западное направление», Ду500»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 25, title: 'ООО «БСК-Строй»', description: '«4-х складских помещений на территории завода филиала ООО «РСХ» в г. Уфа по ул. Производственная,10/1»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 26, title: 'ООО «Элеватор»', description: '«ООО «Маячный элеватор». в с. Маячный, ГО Кумертау, РБ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 27, title: 'ООО «Экосфера»', description: '-Комплекс для термического обезвреживания отходов КТО-150БУР.БМ в Восточно -Сибирском филиале ООО «РН-Бурение -Комплекс для термического обезвреживания отходов КТО-150БУР.БМ в Губкинском филиале ООО «РН-Бурение» -Комплекс для термического обезвреживания отходов КТО-150БУР.БМ в Иркутском филиале ООО «РН-Бурение»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 28, title: 'ОАО «Уфахимчистка»', description: '«Газопровод высокого давления с установкой ГРПШ к котельной ОАО «Уфахимчистка» по адресу ГО г.Уфа, ул. Новоженова 88а»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 29, title: 'ООО ПФ «Уралтрубопроводстройпроект»', description: '«Реконструкция промысловых трубопроводов Суазбашевского, Тепляковского, Арланского нефтяных месторождений»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 30, title: 'ООО «СУ-3 ОАО «Госстрой»', description: '«Группа блокированных жилых домов в п. Зинино»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 31, title: 'ОАО «Гипротрубопровод»', description: '«РВС 10000 м3 №1 ЛПДС «Каркатеевы» Нефтеюганская УМН. Реконструкция» «РВС 10000 м3 №10 ЛПДС «Каркатеевы» Нефтеюганская УМН. Реконструкция»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 32, title: 'ОАО «Оргнефтестрой»', description: '«Реконструкция участка МН «Куйбышев Унеча Мозырь-1» участок Лопатино- 114 км 10-58 км»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 33, title: 'ОАО «Сибнефтепровод»', description: '«РВС 20000 м3 №4 ЛПДС «Саматлор» Нижневартовское УМН. Реконструкция» «РВС 20000 м3 №10 ЛПДС «Саматлор» Нижневартовское УМН. Реконструкция»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 34, title: 'ОАО «Институт Нефтепродуктпроект»', description: '«Обустройство КП СОД (камера приема) на ЛПДС «Соседка» МНПП «Уфа- Западное направление», Ду500»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 35, title: 'Администрация сельского поселения Красноусольский сельский совет МР Гафурийский район, РБ', description: '«Строительство муниципального общественного кладбища в с.Красноусольский, РБ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 36, title: 'ООО «Регион-Ресурс»', description: '«Строительство центра экологического туризма в Кировском районе городского округа г. Уфа Республики Башкортостан»; - разработку Проектной документации в соответствии с требованиями Задания на проектирование и Технических регламентов; - разработку документации, необходимой для прохождения экспертиз и согласований в Государственных надзорных и контрольных службах; - участие в проведении государственной экспертизы Проектной документации, при возникновении необходимости ее проведения.»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 37, title: 'ООО «Новые молочные фермы Башкирии»', description: '«Строительства Молочно-товарного комплекса МТК на 12 110 стойломест и Генетического центра по воспроизводству молочного стада»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 38, title: 'ООО «МД финанс»', description: '«Блок обслуживания по Дуванскому бульвару в микрорайоне «Караидель» в Кировском районе города Уфа»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 39, title: 'ООО «Башнефтехим»', description: '«Строительство четырех железнодорожных путей на площадке «Г» ТСЦ НПЗ ОАО «Газпром нефтехим Салават»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 40, title: 'ООО «Управляющая компания «Альянс Менеджмент Компани»', description: '«Проект перепланировки и внешнего оформления фасада здания, расположенного по адресу: ул. Рижская, д.1 в Ленинском районе г. Уфы»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 41, title: 'МБУ «Управление пожарной охраны ГО г. Уфа Республики Башкортостан', description: '«Здание пожарного депо на 4 выезда по адресу: Ленинский район, п. 8 Марта, РБ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 42, title: 'ООО «Альтернатива»', description: '«Разработка проекта планировки и проекта межевания территории, ограниченной улицами Охотников, Пограничников, Рыбацкой и переулком Удачным в Калининском районе ГО г. Уфа, РБ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 43, title: 'ООО «Башнефтехим»', description: '«Монтаж противопожарного водопровода вдоль проезда №9 между проездами №8 и №10 с подключением КПА, Филиал ОАО АНК «Башнефть» «Башнефть-Уфанефтехим», РБ, г. Уфа»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 44, title: 'ООО «Башнефтехим»', description: '«Внешнее газоснабжение объекта Строительство ПГУ-410Т» промзона г. Салават»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 45, title: 'ООО «Уфанефтемаш»', description: '«Здание дополнительного цеха металлоконструкций по ул. Новая- 3 в д. Мокроусово ГО Уфы»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 46, title: 'ООО ПФ «Уралтрубопроводстройпроект»', description: '«Реконструкция и техническое перевооружение объектов Уренгойского ЗПКТ для переработки конденсата Ачимовских залежей Уренгойского месторождения»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 47, title: 'ООО ПФ «Уралтрубопроводстройпроект»', description: '«Узел отвода противотурбулентной присадки в МК «Уренгой-Сургут»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 48, title: 'ООО ПФ «Уралтрубопроводстройпроект»', description: '«Автоматизированная система пожаротушения и контроля загазованности технологических объектов Уренгойского ЗПКТ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 49, title: 'ООО «Авиапромышленная лизинговая компания»', description: '«Турбаза отдыха «Ясная поляна, г. Уфа, Кировский р-н в районе мелькомбината на левом берегу р. Белой Республики Башкортостан»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 50, title: 'ООО «ЮжноУральскийТехСервис»', description: '«Ст. Злобина 17, Советского района, г. Уфа Республики Башкортостан»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 51, title: 'ООО «Управление капитального строительства «Монолитстрой»', description: '«Административно-торговый развлекательный комплекс в мкр. «Дема-9» в Демском районе ГО г. Уфа, РБ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 52, title: 'ОАО «Уфимский хлопчатобумажный комбинат»', description: '«Колесо обозрения-58 на территории ОАО "Уфимский хлопчатобумажный комбинат" по адресу: г. Уфа, ул. Менделеева, 137»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 53, title: 'ООО «Альфа Проект Уфа»', description: '«Расширение системы газоснабжения п. Нарышево. Строительство кольцующего газопровода высокого и низкого давления по ул. Кооперативная г. Октябрьский с установкой ГРПШ и перекладкой четной стороны д. 57, д. 159. РБ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 54, title: 'ЗАО «Штрабаг»', description: '«Технопарк энергоэффективных технологий на земельном участке в административных границах муниципального района Уфимского района Республики Башкортостан»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 55, title: 'МБОУ СОШ №4 с. Раевский', description: '«Строительство автономной блочной котельной для теплоснабжения МБОУ СОШ №4с. Раевский МР Альшеевский район Республики Башкортостан»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 56, title: 'ООО Инженерный центр «Техпроект»', description: '«Строительство ЛЭП ВЛ-10/0.4 в микрорайоне «Базал» с. Старосубхангулово Бурзянского района Республики Башкортостан»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 57, title: 'ООО «Вектор»', description: '«Реконструкция корп. №17, лит. Ж1, по адресу: г. Уфа, ул. 50 лет СССР д.30»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 58, title: 'МБДОУ детский сад №7 с. Раевский', description: '«Строительство автономной блочной котельной для теплоснабжения МБДОУ детский сад №7 с. Раевский МР Альшеевский район Республики Башкортостан»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 59, title: 'ООО «Уральский экологический научно-производственный институт»', description: '«Строительство социального многоквартирного жилого дома по ул. Вострецова, 7/1 в Калининском районе г. Уфы»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 60, title: 'ООО ПФ «Уралтрубопроводстройпроект»', description: '«Капитальный ремонт трубопроводов ЦДНГ-5,8 (2013г.) (Рассветное, Баклановское месторождение)»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 61, title: 'ООО Инженерный центр «Техпроект»', description: '«Строительство новых и реконструкция действующих сетей и сооружений системы водоснабжения р.ц. Старобалтачево муниципального района Балтачевский район Республики Башкортостан»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 62, title: 'ООО «ПромСтрой»', description: '«Реконструкция автомобильной дороги М-7 "Волга" от Москвы через Владимир, Нижний Новгород, Казань до Уфы на участке км 1270+010 км 1290+838, Республика Башкортостан (II пусковой комплекс)»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 63, title: 'ООО «Промтехстрой»', description: '«Строительство административно-складского здания расположенного по адресу: Республика Башкортостан, г.Уфа, ул. Ростовская, д. 18»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 64, title: 'ООО «Уралстройсервис»', description: '«Подземный гараж с помещениями обслуживания населения на кровле по ул. Российская у пересечения с бульваром Давлеткильдеева в Октябрьском районе городского округа город Уфа РБ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 65, title: 'ООО ПФ «Уралтрубопроводстройпроект»', description: '«Реконструкция склада ЗПКТ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 66, title: 'ООО ПФ «Уралтрубопроводстройпроект»', description: '«Реконструкция систем общезаводского хозяйства Уренгойского ЗПКТ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 67, title: 'ООО ПФ «Уралтрубопроводстройпроект»', description: '«Реконструкция резервуарных парков Уренгойского ЗПКТ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 68, title: 'ООО ПФ «Уралтрубопроводстройпроект»', description: '«Реконструкция установки получения дизельного топлива Уренгойского ЗПКТ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 69, title: 'ООО ПФ «Уралтрубопроводстройпроект»', description: '«Реконструкция установки получения пропан-бутана Уренгойского ЗПКТ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 70, title: 'ООО ПФ «Уралтрубопроводстройпроект»', description: '«Реконструкция установки стабилизации конденсата 1 Уренгойского ЗПКТ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 71, title: 'ООО "ЛУКОЙЛ-ПЕРМЬ"', description: '«Модернизация нефтенасосной станции внешнего транспорта на ПСП "Чернушка"»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 72, title: 'ОАО «Новокуйбышевский нефтеперерабатывающий завод»', description: '«Система измерений количества и показателей качества нефти №1 на входе установки АВТ-11»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 73, title: 'ОАО «Новокуйбышевский нефтеперерабатывающий завод»', description: '«Система измерений количества и показателей качества нефти №2 на входе установки АВТ-11»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 74, title: 'ОАО «Новокуйбышевский нефтеперерабатывающий завод»', description: '«Система измерений количества и показателей качества нефти №3 на входе установки АВТ-11»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 75, title: 'ООО Инженерный центр «ТехПроект»', description: '«Капитальный ремонт ГТС водохранилища на р. Кара-Зирик в с. Верхнеяркеево МР Илишевский район РБ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 76, title: 'ООО Инженерный центр «ТехПроект»', description: '«Капитальный ремонт ГТС пруда на р. Агардинка у с. Агарды МР Благоварский район РБ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 77, title: 'ООО «БСК-Строй»', description: '«4-х складских помещений на территории завода филиала ООО «РСХ» в г. Уфа по ул. Производственная,10/1»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 78, title: 'ООО «РТЗ»', description: '«Проектируемая крановая эстакада. г. Давлеканово, ул. Уральская 89»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 79, title: 'ООО «Блочные котельные»', description: '«Блочно-модульная котельная ОАО «БСК» П/П «2 цех Рассолпромысел»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 80, title: '«Специализированный инвестиционно-потребительский жилищно-строительный кооператив «Благовещенский»', description: '«Жилой дом №2 в микрорайоне №8 г. Благовещенск РБ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 81, title: 'ООО Инженерный центр «Техпроект»', description: '«Строительство резервного водовода в с. Павловка МР Нуримановский район РБ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 82, title: 'ФУ Администрация МР Калтасинский район', description: '«Строительство 12 - квартирного жилого дома в с. Краснохолмский Калтасинского района РБ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 83, title: 'ЗАО ПИИ «Роспроект»', description: '«Реконструкция сельского дома культуры в с . Темясово»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 84, title: 'ООО «ПромБытГазпроект»', description: '«Капитальный ремонт производственной базы Архангельской РЭС» по адресу РБ, Архангельский район, с. Архангельское, ул. Чкалова, 53а, филиала «Центргаз» ОАО «Газсервис»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 85, title: 'ООО «ПромБытГазпроект»', description: '«Блочная газовая котельная МБОУ СОШ в с. Красный ключ Нуримановского района Республики Башкортостан»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 86, title: 'ООО «ПромБытГазпроект»', description: '«Металлический склад г. Кумертау, Республика Башкортостан»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 87, title: 'ООО «РаушБиер»', description: '«Двухэтажный ресторанный комплекс, расположенный по адресу: Республика Башкортостан, г.Туймазы, ул. Тукаева, д. 8»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 88, title: 'ООО «Региональная строительная компания»', description: '«Пристрой к зданию школы по адресу РБ, Янаульский р-н, с.Истяк, ул. Школьная 1а»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 89, title: 'ООО СМУ «Уралстройсервис»', description: '«Строительство 12 - квартирного жилого дома в с. Краснохолмский Калтасинского района РБ»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 90, title: 'ООО СОК «Трамплин»', description: '«Бугельный подъемник в Октябрьском районе, г. Уфа Республика Башкортостан»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 91, title: 'ООО «Уфанефтемаш»', description: '«Здание дополнительного цеха металлоконструкций по ул. Новая-3, в д. Мокроусово ГО Уфы»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 92, title: 'ООО "Фирма РОССИ"', description: '«Площадка хранения баллонов сжиженных газов на территории ООО «Русджам-Холдинг» в г. Уфе»', image: 'https://placehold.co/600x400/94a3b8/white' },
{ id: 93, title: 'Администрация сельского поселения Зубовский сельсовет Муниципального Района Уфимский район РБ', description: 'Строительство газопровода высокого давления, низкого давления и ПГБ для газоснабжения жилых домов по ул. Снежная в с. Зубово, ул.Центральная в с.Нижегородка Уфимского района РБ', image: 'https://placehold.co/600x400/94a3b8/white' }
];
// Функция для определения категории проекта
function categorizeProject(project: ProjectItem): string {
const text = (project.title + ' ' + project.description).toLowerCase();
if (text.includes('нефт') || text.includes('газ') || text.includes('рвс') ||
text.includes('лпдс') || text.includes('трубопровод') || text.includes('зпкт') ||
text.includes('скваж') || text.includes('нгду') || text.includes('конденсат')) {
return 'Нефтегазовая промышленность';
}
if (text.includes('жилой дом') || text.includes('жилых дом') || text.includes('жк') ||
text.includes('квартир') || text.includes('жэу')) {
return 'Жилищное строительство';
}
if (text.includes('газопровод') || text.includes('водопровод') || text.includes('водовод') ||
text.includes('электр') || text.includes('лэп') || text.includes('дорог') ||
text.includes('волс') || text.includes('связь') || text.includes('водоснабжен') ||
text.includes('гтс')) {
return 'Инфраструктура и коммуникации';
}
if (text.includes('школ') || text.includes('детский сад') || text.includes('культур') ||
text.includes('спорт') || text.includes('физкультурно') || text.includes('брги') ||
text.includes('мбоу') || text.includes('мбдоу') || text.includes('кладбищ')) {
return 'Социальные объекты';
}
if (text.includes('склад') || text.includes('цех') || text.includes('завод') ||
text.includes('производств') || text.includes('промышлен') || text.includes('элеватор') ||
text.includes('котельн') || text.includes('эстакад') || text.includes('база')) {
return 'Промышленные и складские объекты';
}
if (text.includes('ресторан') || text.includes('kfc') || text.includes('азс') ||
text.includes('торгов') || text.includes('администрат') || text.includes('офис') ||
text.includes('турбаза') || text.includes('туризм') || text.includes('развлекательн') ||
text.includes('колесо обозрения') || text.includes('технопарк') || text.includes('депо') ||
text.includes('гараж') || text.includes('подъемник')) {
return 'Коммерческая недвижимость и туризм';
}
return 'Прочие объекты';
}
// Группировка проектов по категориям
export function groupProjectsByCategory(): ProjectCategory[] {
const categories: { [key: string]: ProjectItem[] } = {};
PROJECTS.forEach(project => {
const category = categorizeProject(project);
if (!categories[category]) {
categories[category] = [];
}
categories[category].push(project);
});
return Object.entries(categories)
.map(([name, projects]) => ({ name, projects }))
.sort((a, b) => b.projects.length - a.projects.length);
}
export const STEPS: StepItem[] = [
{
icon: Phone,
title: 'Звонок',
description: 'Связываемся с клиентом и уточняем все детали, далее определяем цену'
},
{
icon: FileText,
title: 'ТЗ',
description: 'Составляем техническое задание для наших специалистов'
},
{
icon: Briefcase,
title: 'Договор',
description: 'Подготавливаем все необходимые документы и заключаем договор'
},
{
icon: HardHat,
title: 'Работа',
description: 'Выполняем работу на участке, испытываем отобранные образцы'
},
{
icon: DraftingCompass,
title: 'Отчет',
description: 'Разрабатываем технический отчет и передаем пакет документов'
},
{
icon: MessageSquare,
title: 'Финал',
description: 'Презентуем отчет и даем рекомендации'
}
];

BIN
dist/assets/geo-logo-CTcDXZQa.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

1
dist/assets/index-BZSFOg8v.css vendored Normal file
View File

@@ -0,0 +1 @@
*{margin:0;padding:0;box-sizing:border-box}body{font-family:Inter,sans-serif}.overflow-x-auto{scrollbar-width:thin;scrollbar-color:#FF9900 #f5f5f5}.overflow-x-auto::-webkit-scrollbar{height:8px}.overflow-x-auto::-webkit-scrollbar-track{background:#f5f5f5;border-radius:10px}.overflow-x-auto::-webkit-scrollbar-thumb{background:#f90;border-radius:10px}.overflow-x-auto::-webkit-scrollbar-thumb:hover{background:#e68a00}.line-clamp-2{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.scrollbar-hide{-ms-overflow-style:none;scrollbar-width:none}.scrollbar-hide::-webkit-scrollbar{display:none}@keyframes gradient-shift{0%{background-position:0% 50%}50%{background-position:100% 50%}to{background-position:0% 50%}}.animate-gradient{background-size:200% 200%;animation:gradient-shift 8s ease infinite}@keyframes fade-in-up{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.animate-fade-in-up{animation:fade-in-up .6s ease-out forwards}

361
dist/assets/index-WgNyvlZq.js vendored Normal file

File diff suppressed because one or more lines are too long

104
dist/index.html vendored Normal file
View File

@@ -0,0 +1,104 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ГеоВектор - Проектирование и Строительство</title>
<!-- Favicon -->
<link rel="icon" type="image/webp" href="/assets/geo-logo-CTcDXZQa.webp" />
<link rel="shortcut icon" type="image/webp" href="/assets/geo-logo-CTcDXZQa.webp" />
<link rel="apple-touch-icon" href="/assets/geo-logo-CTcDXZQa.webp" />
<!-- Meta tags -->
<meta name="description" content="ООО ГеоВектор - профессиональные инженерные изыскания, проектирование и строительство в Уфе. Современное оборудование, опытные специалисты." />
<meta name="keywords" content="инженерные изыскания, проектирование, строительство, геология, геодезия, ГеоВектор, Уфа" />
<!-- Open Graph для соцсетей -->
<meta property="og:title" content="ГеоВектор - Инженерные изыскания, проектирование и строительство" />
<meta property="og:description" content="Профессиональные инженерные изыскания, проектирование и строительство в Уфе. Современное оборудование, опытные специалисты." />
<meta property="og:image" content="https://geowektor.ru/media/geo-logo.webp" />
<meta property="og:url" content="https://geowektor.ru" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="ru_RU" />
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="ГеоВектор - Инженерные изыскания и строительство" />
<meta name="twitter:description" content="Профессиональные решения для строительства в Уфе" />
<meta name="twitter:image" content="https://geowektor.ru/media/geo-logo.webp" />
<!-- Schema.org разметка -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "ООО ГеоВектор",
"alternateName": "GeoVector",
"url": "https://geowektor.ru",
"logo": "https://geowektor.ru/media/geo-logo.webp",
"contactPoint": {
"@type": "ContactPoint",
"telephone": "+7-347-292-73-70",
"contactType": "customer service",
"areaServed": "RU",
"availableLanguage": ["Russian"]
},
"address": {
"@type": "PostalAddress",
"streetAddress": "ул. Комсомольская 19/1",
"addressLocality": "Уфа",
"addressRegion": "Республика Башкортостан",
"postalCode": "450001",
"addressCountry": "RU"
},
"sameAs": [
"https://t.me/ooo_geo_wektor",
"https://vk.com/geowektor_ru"
],
"description": "Профессиональные инженерные изыскания, проектирование и строительство. Грунтовая и радиационная лаборатории."
}
</script>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'sans-serif'],
},
colors: {
brand: {
orange: '#FF9900',
dark: '#111111',
gray: '#222222',
light: '#F5F5F5'
}
}
}
}
}
</script>
<script type="importmap">
{
"imports": {
"lucide-react": "https://aistudiocdn.com/lucide-react@^0.555.0",
"react/": "https://aistudiocdn.com/react@^19.2.0/",
"react": "https://aistudiocdn.com/react@^19.2.0",
"react-dom/": "https://aistudiocdn.com/react-dom@^19.2.0/",
"react-router-dom": "https://aistudiocdn.com/react-router-dom@^6.22.3",
"react-router": "https://aistudiocdn.com/react-router@^6.22.3",
"@remix-run/router": "https://aistudiocdn.com/@remix-run/router@^1.15.3"
}
}
</script>
<script type="module" crossorigin src="/assets/index-WgNyvlZq.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BZSFOg8v.css">
</head>
<body>
<div id="root"></div>
</body>
</html>

19
dist/robots.txt vendored Normal file
View File

@@ -0,0 +1,19 @@
User-agent: *
Allow: /
# Sitemap
Sitemap: https://geowektor.ru/sitemap.xml
# Запрет индексации служебных файлов
Disallow: /node_modules/
Disallow: /*.json
Disallow: /*.ts
Disallow: /*.tsx
# Доступ к медиа файлам
Allow: /media/
# Host (основной домен)
Host: https://geowektor.ru

107
dist/sitemap.xml vendored Normal file
View File

@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://geowektor.ru/</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://geowektor.ru/#/about</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://geowektor.ru/#/services</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>weekly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://geowektor.ru/#/services/surveying</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://geowektor.ru/#/services/design</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://geowektor.ru/#/services/construction</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://geowektor.ru/#/services/soil-survey</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://geowektor.ru/#/services/building-survey</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://geowektor.ru/#/services/land-survey</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://geowektor.ru/#/services/technical-tasks</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.6</priority>
</url>
<url>
<loc>https://geowektor.ru/#/projects</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://geowektor.ru/#/fleet</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://geowektor.ru/#/laboratories/soil</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://geowektor.ru/#/laboratories/radiation</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://geowektor.ru/#/certificates</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://geowektor.ru/#/contacts</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://geowektor.ru/#/privacy-policy</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>yearly</changefreq>
<priority>0.5</priority>
</url>
</urlset>

67
dist/sw.js vendored Normal file
View File

@@ -0,0 +1,67 @@
const CACHE_NAME = 'geovector-v1';
const urlsToCache = [
'/',
'/index.html',
'/index.css',
'/media/geo-logo.webp',
'/media/qr-code.png'
];
// Установка Service Worker
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then((cache) => {
console.log('Кэш открыт');
return cache.addAll(urlsToCache);
})
);
self.skipWaiting();
});
// Активация Service Worker
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName !== CACHE_NAME) {
console.log('Удаление старого кэша:', cacheName);
return caches.delete(cacheName);
}
})
);
})
);
return self.clients.claim();
});
// Fetch - стратегия Network First, затем Cache
self.addEventListener('fetch', (event) => {
event.respondWith(
fetch(event.request)
.then((response) => {
// Клонируем ответ, так как можем использовать его только один раз
const responseToCache = response.clone();
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, responseToCache);
});
return response;
})
.catch(() => {
// Если сеть недоступна, пытаемся получить из кэша
return caches.match(event.request).then((cachedResponse) => {
if (cachedResponse) {
return cachedResponse;
}
// Если нет в кэше, возвращаем офлайн-страницу
return caches.match('/index.html');
});
})
);
});

86
index.css Normal file
View File

@@ -0,0 +1,86 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
}
/* Плавная прокрутка для миниатюр карусели */
.overflow-x-auto {
scrollbar-width: thin;
scrollbar-color: #FF9900 #f5f5f5;
}
.overflow-x-auto::-webkit-scrollbar {
height: 8px;
}
.overflow-x-auto::-webkit-scrollbar-track {
background: #f5f5f5;
border-radius: 10px;
}
.overflow-x-auto::-webkit-scrollbar-thumb {
background: #FF9900;
border-radius: 10px;
}
.overflow-x-auto::-webkit-scrollbar-thumb:hover {
background: #e68a00;
}
/* Обрезка текста */
.line-clamp-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* Скрытие скроллбара для каруселей */
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
/* Градиентная анимация для Hero */
@keyframes gradient-shift {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
.animate-gradient {
background-size: 200% 200%;
animation: gradient-shift 8s ease infinite;
}
/* Плавное появление элементов */
@keyframes fade-in-up {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-fade-in-up {
animation: fade-in-up 0.6s ease-out forwards;
}

103
index.html Normal file
View File

@@ -0,0 +1,103 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ГеоВектор - Проектирование и Строительство</title>
<!-- Favicon -->
<link rel="icon" type="image/webp" href="/media/geo-logo.webp" />
<link rel="shortcut icon" type="image/webp" href="/media/geo-logo.webp" />
<link rel="apple-touch-icon" href="/media/geo-logo.webp" />
<!-- Meta tags -->
<meta name="description" content="ООО ГеоВектор - профессиональные инженерные изыскания, проектирование и строительство в Уфе. Современное оборудование, опытные специалисты." />
<meta name="keywords" content="инженерные изыскания, проектирование, строительство, геология, геодезия, ГеоВектор, Уфа" />
<!-- Open Graph для соцсетей -->
<meta property="og:title" content="ГеоВектор - Инженерные изыскания, проектирование и строительство" />
<meta property="og:description" content="Профессиональные инженерные изыскания, проектирование и строительство в Уфе. Современное оборудование, опытные специалисты." />
<meta property="og:image" content="https://geowektor.ru/media/geo-logo.webp" />
<meta property="og:url" content="https://geowektor.ru" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="ru_RU" />
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="ГеоВектор - Инженерные изыскания и строительство" />
<meta name="twitter:description" content="Профессиональные решения для строительства в Уфе" />
<meta name="twitter:image" content="https://geowektor.ru/media/geo-logo.webp" />
<!-- Schema.org разметка -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "ООО ГеоВектор",
"alternateName": "GeoVector",
"url": "https://geowektor.ru",
"logo": "https://geowektor.ru/media/geo-logo.webp",
"contactPoint": {
"@type": "ContactPoint",
"telephone": "+7-347-292-73-70",
"contactType": "customer service",
"areaServed": "RU",
"availableLanguage": ["Russian"]
},
"address": {
"@type": "PostalAddress",
"streetAddress": "ул. Комсомольская 19/1",
"addressLocality": "Уфа",
"addressRegion": "Республика Башкортостан",
"postalCode": "450001",
"addressCountry": "RU"
},
"sameAs": [
"https://t.me/ooo_geo_wektor",
"https://vk.com/geowektor_ru"
],
"description": "Профессиональные инженерные изыскания, проектирование и строительство. Грунтовая и радиационная лаборатории."
}
</script>
<script src="js/tailwind.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'sans-serif'],
},
colors: {
brand: {
orange: '#FF9900',
dark: '#111111',
gray: '#222222',
light: '#F5F5F5'
}
}
}
}
}
</script>
<script type="importmap">
{
"imports": {
"lucide-react": "https://aistudiocdn.com/lucide-react@^0.555.0",
"react/": "https://aistudiocdn.com/react@^19.2.0/",
"react": "https://aistudiocdn.com/react@^19.2.0",
"react-dom/": "https://aistudiocdn.com/react-dom@^19.2.0/",
"react-router-dom": "https://aistudiocdn.com/react-router-dom@^6.22.3",
"react-router": "https://aistudiocdn.com/react-router@^6.22.3",
"@remix-run/router": "https://aistudiocdn.com/@remix-run/router@^1.15.3"
}
}
</script>
<link rel="stylesheet" href="/index.css">
</head>
<body>
<div id="root"></div>
<script type="module" src="/index.tsx"></script>
</body>
</html>

19
index.tsx Normal file
View File

@@ -0,0 +1,19 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { registerServiceWorker } from './registerSW';
const rootElement = document.getElementById('root');
if (!rootElement) {
throw new Error("Could not find root element to mount to");
}
const root = ReactDOM.createRoot(rootElement);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// Регистрируем Service Worker
registerServiceWorker();

64
js/tailwind.js Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
media/certs/cro-build.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

BIN
media/certs/pp-credo.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
media/feedback/1.pdf Normal file

Binary file not shown.

BIN
media/feedback/2.pdf Normal file

Binary file not shown.

BIN
media/feedback/3.pdf Normal file

Binary file not shown.

BIN
media/feedback/4.pdf Normal file

Binary file not shown.

BIN
media/feedback/5.pdf Normal file

Binary file not shown.

BIN
media/feedback/6.pdf Normal file

Binary file not shown.

BIN
media/feedback/7.pdf Normal file

Binary file not shown.

BIN
media/feedback/8.pdf Normal file

Binary file not shown.

BIN
media/geo-logo.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
media/qr-code.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Some files were not shown because too many files have changed in this diff Show More