diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..f78d97f --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "tabWidth": 2, + "printWidth": 120, + "useTabs": false, + "semi": false, + "singleQuote": true, + "trailingComma": "es5", + "bracketSpacing": true, + "arrowParens": "avoid" +} diff --git a/package-lock.json b/package-lock.json index 4042b2e..1aa2547 100644 --- a/package-lock.json +++ b/package-lock.json @@ -58,12 +58,13 @@ "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@vitejs/plugin-react": "^4.7.0", + "prettier": "^3.8.1", "tailwindcss": "^4.1.12", "typescript": "~5.6.3", "vite": "^6.3.5" }, "engines": { - "node": ">=18.0.0 <22.0.0", + "node": ">=18.0.0", "npm": ">=9.0.0" } }, @@ -4286,6 +4287,22 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", diff --git a/package.json b/package.json index 5317a14..768960e 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@vitejs/plugin-react": "^4.7.0", + "prettier": "^3.8.1", "tailwindcss": "^4.1.12", "typescript": "~5.6.3", "vite": "^6.3.5" diff --git a/src/App.tsx b/src/App.tsx index 38e14f6..3b164a1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,159 +1,130 @@ -import { useState, useEffect } from "react"; -import { Header } from "./components/Header"; -import { Footer } from "./components/Footer"; -import { ContactModal } from "./components/ContactModal"; -import { HomePage } from "./pages/HomePage"; -import { CloudPage } from "./pages/CloudPage"; -import { RussianSoftwarePage } from "./pages/RussianSoftwarePage"; -import { CybersecurityPage } from "./pages/CybersecurityPage"; -import { AISolutionsPage } from "./pages/AISolutionsPage"; -import { RussianHardwarePage } from "./pages/RussianHardwarePage"; -import { HardwareSolutionsPage } from "./pages/HardwareSolutionsPage"; -import { CADandGISPage } from "./pages/CADandGISPage"; -import { IndustrialSolutionsPage } from "./pages/IndustrialSolutionsPage"; -import { GovernmentPage } from "./pages/GovernmentPage"; -import { BusinessPage } from "./pages/BusinessPage"; -import { ConsultingPage } from "./pages/ConsultingPage"; -import { ImplementationPage } from "./pages/ImplementationPage"; -import { ManagedServicesPage } from "./pages/ManagedServicesPage"; -import { IntegrationPage } from "./pages/IntegrationPage"; -import { SpecializedServicesPage } from "./pages/SpecializedServicesPage"; -import { SupportPage } from "./pages/SupportPage"; -import { SubscriptionPage } from "./pages/SubscriptionPage"; +import { useState, useEffect } from 'react' +import { Header } from './components/Header' +import { Footer } from './components/Footer' +import { ContactModal } from './components/ContactModal' +import { HomePage } from './pages/HomePage' +import { CloudPage } from './pages/CloudPage' +import { RussianSoftwarePage } from './pages/RussianSoftwarePage' +import { CybersecurityPage } from './pages/CybersecurityPage' +import { AISolutionsPage } from './pages/AISolutionsPage' +import { RussianHardwarePage } from './pages/RussianHardwarePage' +import { HardwareSolutionsPage } from './pages/HardwareSolutionsPage' +import { CADandGISPage } from './pages/CADandGISPage' +import { IndustrialSolutionsPage } from './pages/IndustrialSolutionsPage' +import { GovernmentPage } from './pages/GovernmentPage' +import { BusinessPage } from './pages/BusinessPage' +import { ConsultingPage } from './pages/ConsultingPage' +import { ImplementationPage } from './pages/ImplementationPage' +import { ManagedServicesPage } from './pages/ManagedServicesPage' +import { IntegrationPage } from './pages/IntegrationPage' +import { SpecializedServicesPage } from './pages/SpecializedServicesPage' +import { SupportPage } from './pages/SupportPage' +import { SubscriptionPage } from './pages/SubscriptionPage' export default function App() { - const [currentPage, setCurrentPage] = useState("home"); - const [pendingScroll, setPendingScroll] = useState< - string | null - >(null); - const [isContactModalOpen, setIsContactModalOpen] = - useState(false); + const [currentPage, setCurrentPage] = useState('home') + const [pendingScroll, setPendingScroll] = useState(null) + const [isContactModalOpen, setIsContactModalOpen] = useState(false) const scrollToSection = (sectionId: string) => { // Даем странице время отрендериться setTimeout(() => { - const section = document.getElementById(sectionId); - console.log( - "Trying to scroll to:", - sectionId, - "Found element:", - section, - ); + const section = document.getElementById(sectionId) + console.log('Trying to scroll to:', sectionId, 'Found element:', section) if (section) { - const headerHeight = 85; // Header высота + минимальный отступ - const targetPosition = section.offsetTop - headerHeight; - console.log("Scrolling to position:", targetPosition); + const headerHeight = 85 // Header высота + минимальный отступ + const targetPosition = section.offsetTop - headerHeight + console.log('Scrolling to position:', targetPosition) window.scrollTo({ top: targetPosition, - behavior: "smooth", - }); + behavior: 'smooth', + }) } else { - console.error("Section not found:", sectionId); + console.error('Section not found:', sectionId) } - }, 100); - }; + }, 100) + } const handleNavigate = (page: string, section?: string) => { if (section) { // Клик на Кейсы/О компании/Контакты - if (currentPage !== "home") { + if (currentPage !== 'home') { // Если не на главной - переходим туда - setCurrentPage("home"); - setPendingScroll(section); + setCurrentPage('home') + setPendingScroll(section) } else { // Уже на главной - скроллим сразу - scrollToSection(section); + scrollToSection(section) } } else { // Обычная навигация на другие страницы - setCurrentPage(page); - setPendingScroll(null); - window.scrollTo({ top: 0, behavior: "smooth" }); + setCurrentPage(page) + setPendingScroll(null) + window.scrollTo({ top: 0, behavior: 'smooth' }) } - }; + } useEffect(() => { // Когда вернулись на главную с отложенным скроллом - if (currentPage === "home" && pendingScroll) { - scrollToSection(pendingScroll); - setPendingScroll(null); + if (currentPage === 'home' && pendingScroll) { + scrollToSection(pendingScroll) + setPendingScroll(null) } - }, [currentPage, pendingScroll]); + }, [currentPage, pendingScroll]) const handleBackToHome = () => { - setCurrentPage("home"); - setPendingScroll(null); - window.scrollTo({ top: 0, behavior: "smooth" }); - }; + setCurrentPage('home') + setPendingScroll(null) + window.scrollTo({ top: 0, behavior: 'smooth' }) + } const renderPage = () => { switch (currentPage) { - case "cloud": - return ; - case "russian-software": - return ( - - ); - case "cybersecurity": - return ; - case "ai-solutions": - return ; - case "russian-hardware": - return ( - - ); - case "hardware-solutions": - return ( - - ); - case "cad-gis": - return ; - case "industrial-solutions": - return ( - - ); - case "government": - return ; - case "business": - return ; - case "consulting": - return ; - case "implementation": - return ; - case "managed-services": - return ( - - ); - case "integration": - return ; - case "specialized-services": - return ( - - ); - case "support": - return ; - case "subscription": - return ; + case 'cloud': + return + case 'russian-software': + return + case 'cybersecurity': + return + case 'ai-solutions': + return + case 'russian-hardware': + return + case 'hardware-solutions': + return + case 'cad-gis': + return + case 'industrial-solutions': + return + case 'government': + return + case 'business': + return + case 'consulting': + return + case 'implementation': + return + case 'managed-services': + return + case 'integration': + return + case 'specialized-services': + return + case 'support': + return + case 'subscription': + return default: - return ( - - setIsContactModalOpen(true) - } - /> - ); + return setIsContactModalOpen(true)} /> } - }; + } return (
{renderPage()}
- setIsContactModalOpen(false)} - /> + setIsContactModalOpen(false)} />
- ); -} \ No newline at end of file + ) +} diff --git a/src/components/About.tsx b/src/components/About.tsx index 4949fb7..19dec1d 100644 --- a/src/components/About.tsx +++ b/src/components/About.tsx @@ -1,5 +1,24 @@ -import { CheckCircle, Rocket, Zap, Target, Award, Shield, Clock, HeadphonesIcon, TrendingUp, Users, CheckCircle2, Cloud, Lock, Database, Briefcase, Server, Cpu, Package } from 'lucide-react'; -import { useState, useEffect } from 'react'; +import { + CheckCircle, + Rocket, + Zap, + Target, + Award, + Shield, + Clock, + HeadphonesIcon, + TrendingUp, + Users, + CheckCircle2, + Cloud, + Lock, + Database, + Briefcase, + Server, + Cpu, + Package, +} from 'lucide-react' +import { useState, useEffect } from 'react' const allVendors = [ 'Яндекс.Облако', @@ -53,36 +72,34 @@ const allVendors = [ 'Depo', 'Eltex', 'Qtech', - 'D-Link' -]; + 'D-Link', +] export function About() { - const [currentVendorIndex, setCurrentVendorIndex] = useState(0); - const [isVisible, setIsVisible] = useState(true); + const [currentVendorIndex, setCurrentVendorIndex] = useState(0) + const [isVisible, setIsVisible] = useState(true) useEffect(() => { const interval = setInterval(() => { - setIsVisible(false); - - setTimeout(() => { - setCurrentVendorIndex((prev) => (prev + 1) % allVendors.length); - setIsVisible(true); - }, 800); - }, 4500); + setIsVisible(false) - return () => clearInterval(interval); - }, []); + setTimeout(() => { + setCurrentVendorIndex(prev => (prev + 1) % allVendors.length) + setIsVisible(true) + }, 800) + }, 4500) + + return () => clearInterval(interval) + }, []) return (
-

- О компании -

+

О компании

Сотрудничаем с - @@ -158,5 +175,5 @@ export function About() {

- ); -} \ No newline at end of file + ) +} diff --git a/src/components/Cases.tsx b/src/components/Cases.tsx index c793d0d..8b58e71 100644 --- a/src/components/Cases.tsx +++ b/src/components/Cases.tsx @@ -1,4 +1,4 @@ -import { ArrowRight, Cloud, Cpu, Shield } from 'lucide-react'; +import { ArrowRight, Cloud, Cpu, Shield } from 'lucide-react' const cases = [ { @@ -10,7 +10,7 @@ const cases = [ results: '−40% TCO', gradient: 'from-blue-100 to-cyan-100', iconBg: 'bg-white', - iconColor: 'text-blue-600' + iconColor: 'text-blue-600', }, { icon: Cpu, @@ -21,7 +21,7 @@ const cases = [ results: '+25% эффективность', gradient: 'from-emerald-100 to-teal-100', iconBg: 'bg-white', - iconColor: 'text-emerald-600' + iconColor: 'text-emerald-600', }, { icon: Shield, @@ -32,37 +32,36 @@ const cases = [ results: '99.9% uptime', gradient: 'from-violet-100 to-purple-100', iconBg: 'bg-white', - iconColor: 'text-violet-600' - } -]; + iconColor: 'text-violet-600', + }, +] export function Cases() { return (
-

- Кейсы -

-

- Реализованные проекты -

-

- Примеры успешного внедрения с конкретными результатами -

+

Кейсы

+

Реализованные проекты

+

Примеры успешного внедрения с конкретными результатами

{cases.map((caseItem, index) => { - const Icon = caseItem.icon; - const floatClass = index === 0 ? 'animate-float' : index === 1 ? 'animate-float-delay-1' : 'animate-float-delay-2'; + const Icon = caseItem.icon + const floatClass = + index === 0 ? 'animate-float' : index === 1 ? 'animate-float-delay-1' : 'animate-float-delay-2' return (
-
-
+
+
@@ -71,29 +70,21 @@ export function Cases() {
- +
-
- {caseItem.company} -
- -

- {caseItem.title} -

- -

- {caseItem.description} -

- +
{caseItem.company}
+ +

{caseItem.title}

+ +

{caseItem.description}

+
- - {caseItem.results} - + {caseItem.results}
- ); + ) })}
@@ -105,5 +96,5 @@ export function Cases() {
- ); -} \ No newline at end of file + ) +} diff --git a/src/components/CategoryPage.tsx b/src/components/CategoryPage.tsx index a0f1699..f6f2506 100644 --- a/src/components/CategoryPage.tsx +++ b/src/components/CategoryPage.tsx @@ -1,17 +1,17 @@ -import { ArrowLeft } from 'lucide-react'; +import { ArrowLeft } from 'lucide-react' interface Vendor { - name: string; - description: string; - logo?: string; - products?: string[]; + name: string + description: string + logo?: string + products?: string[] } interface CategoryPageProps { - title: string; - description: string; - vendors: Vendor[]; - onBack: () => void; + title: string + description: string + vendors: Vendor[] + onBack: () => void } export function CategoryPage({ title, description, vendors, onBack }: CategoryPageProps) { @@ -20,27 +20,23 @@ export function CategoryPage({ title, description, vendors, onBack }: CategoryPa {/* Hero секция */}
- - +
Каталог решений
-

- {title} -

-

- {description} -

+

{title}

+

{description}

- +
@@ -50,32 +46,23 @@ export function CategoryPage({ title, description, vendors, onBack }: CategoryPa
{vendors.map((vendor, index) => ( -
-

- {vendor.name} -

+

{vendor.name}

- -

- {vendor.description} -

+ +

{vendor.description}

{vendor.products && vendor.products.length > 0 && (
-
- Решения -
+
Решения
{vendor.products.map((product, idx) => ( - + {product} ))} @@ -92,5 +79,5 @@ export function CategoryPage({ title, description, vendors, onBack }: CategoryPa
- ); -} \ No newline at end of file + ) +} diff --git a/src/components/Contact.tsx b/src/components/Contact.tsx index 1e0b3fc..969a3e4 100644 --- a/src/components/Contact.tsx +++ b/src/components/Contact.tsx @@ -1,4 +1,4 @@ -import { Phone, Mail, MapPin, Clock } from 'lucide-react'; +import { Phone, Mail, MapPin, Clock } from 'lucide-react' export function Contact() { return ( @@ -6,12 +6,8 @@ export function Contact() {
{/* Заголовок */}
-

- Обсудим ваш проект -

-

- Оставьте заявку — перезвоним в течение часа -

+

Обсудим ваш проект

+

Оставьте заявку — перезвоним в течение часа

{/* Форма */} @@ -76,9 +72,7 @@ export function Contact() { > Отправить заявку -

- Нажимая кнопку, вы соглашаетесь с политикой конфиденциальности -

+

Нажимая кнопку, вы соглашаетесь с политикой конфиденциальности

@@ -104,5 +98,5 @@ export function Contact() {
- ); -} \ No newline at end of file + ) +} diff --git a/src/components/ContactModal.tsx b/src/components/ContactModal.tsx index 7418b35..f095eda 100644 --- a/src/components/ContactModal.tsx +++ b/src/components/ContactModal.tsx @@ -1,44 +1,40 @@ -import { X, Mail, Phone, MapPin, Clock, Calendar } from 'lucide-react'; -import { useEffect, useState } from 'react'; -import { createPortal } from 'react-dom'; +import { X, Mail, Phone, MapPin, Clock, Calendar } from 'lucide-react' +import { useEffect, useState } from 'react' +import { createPortal } from 'react-dom' interface ContactModalProps { - isOpen: boolean; - onClose: () => void; + isOpen: boolean + onClose: () => void } export function ContactModal({ isOpen, onClose }: ContactModalProps) { useEffect(() => { if (isOpen) { - document.body.style.overflow = 'hidden'; + document.body.style.overflow = 'hidden' } else { - document.body.style.overflow = 'unset'; + document.body.style.overflow = 'unset' } return () => { - document.body.style.overflow = 'unset'; - }; - }, [isOpen]); + document.body.style.overflow = 'unset' + } + }, [isOpen]) - if (!isOpen) return null; + if (!isOpen) return null const modalContent = ( -
-
e.stopPropagation()} +
e.stopPropagation()} > {/* Заголовок */}
-

- Обсудим ваш проект -

-

- Оставьте заявку — перезвоним в течение часа -

+

Обсудим ваш проект

+

Оставьте заявку — перезвоним в течение часа