Добавить пререндер, партнёров, реквизиты, SEO-улучшения

- SSR-пререндер через Vite + react-dom/server (entry-server.jsx, scripts/prerender.mjs)
- Секция партнёров: RU-CENTER, REG.RU, МТВ, КОНТУР
- Реквизиты компании в футере (ИНН, ОГРН, банк)
- Копирайт с 2011 года
- Логотип увеличен (h-8→h-12 навбар, h-7→h-10 футер)
- favicon.ico пересобран с 16×16, 32×32, 48×48 из logo.png
- og:image и twitter:image переключены на .png
- apple-touch-icon.png и og-image.png сгенерированы через sharp
- SSR-safe: localStorage и window.location проверяются на typeof

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-14 05:24:01 +03:00
parent 0804264d3b
commit 3cb42a4466
16 changed files with 729 additions and 11 deletions

View File

@@ -14,7 +14,7 @@ function LangSync() {
}
function Router() {
const [path, setPath] = useState(window.location.pathname)
const [path, setPath] = useState(typeof window !== 'undefined' ? window.location.pathname : '/')
useEffect(() => {
const handler = () => setPath(window.location.pathname)
window.addEventListener('popstate', handler)

View File

@@ -3,13 +3,14 @@ import { useLanguage } from '../contexts/LanguageContext.jsx'
export default function Footer() {
const { t } = useLanguage()
const year = new Date().getFullYear()
const year = `2011 ${new Date().getFullYear()}`
const phones = t('contact.phones')
return (
<footer className="bg-slate-900 text-slate-400 py-10">
<div className="max-w-6xl mx-auto px-4 sm:px-6 flex flex-col md:flex-row items-center justify-between gap-4">
<img src="/logo.png" alt="Сисадмингрупп" className="h-7 w-auto brightness-0 invert" />
<footer className="bg-slate-900 text-slate-400">
{/* Main footer row */}
<div className="max-w-6xl mx-auto px-4 sm:px-6 py-10 flex flex-col md:flex-row items-center justify-between gap-4">
<img src="/logo.png" alt="Сисадмингрупп" className="h-10 w-auto brightness-0 invert" />
<span className="text-sm">{year} © {t('footer.rights')}</span>
<div className="flex flex-wrap justify-center gap-x-6 gap-y-1 text-sm">
{phones.map((p, i) => (
@@ -18,6 +19,15 @@ export default function Footer() {
<a href="mailto:info@sag24.ru" className="hover:text-white transition-colors">info@sag24.ru</a>
</div>
</div>
{/* Legal details */}
<div className="border-t border-slate-800">
<div className="max-w-6xl mx-auto px-4 sm:px-6 py-6 text-xs text-slate-600 leading-relaxed">
<p className="mb-1">ООО «Сисадмингрупп» · ИНН 5038080741 · КПП 503801001 · ОГРН 1115038000890</p>
<p className="mb-1">Юридический адрес: 141207, Россия, Московская область, г. Пушкино, пр-кт Московский, д. 38/14, кв. 33</p>
<p>Р/с 40702810510000179731 · АО «ТБанк» · БИК 044525974 · К/с 30101810145250000974</p>
</div>
</div>
</footer>
)
}

View File

@@ -16,7 +16,7 @@ export default function Navigation() {
<header className="fixed top-0 left-0 right-0 z-50 bg-white shadow-sm">
<div className="max-w-6xl mx-auto px-4 sm:px-6 h-16 flex items-center justify-between">
<a href="#" className="flex items-center">
<img src="/logo.png" alt="Сисадмингрупп" className="h-8 w-auto" />
<img src="/logo.png" alt="Сисадмингрупп" className="h-12 w-auto" />
</a>
{/* Desktop nav */}

View File

@@ -7,13 +7,13 @@ const LanguageContext = createContext(null)
export function LanguageProvider({ children }) {
const [lang, setLang] = useState(() => {
return localStorage.getItem('lang') || 'ru'
return (typeof localStorage !== 'undefined' && localStorage.getItem('lang')) || 'ru'
})
const toggle = () => {
const next = lang === 'ru' ? 'en' : 'ru'
setLang(next)
localStorage.setItem('lang', next)
if (typeof localStorage !== 'undefined') localStorage.setItem('lang', next)
}
const t = (key) => {

7
src/entry-server.jsx Normal file
View File

@@ -0,0 +1,7 @@
import React from 'react'
import { renderToString } from 'react-dom/server'
import App from './App.jsx'
export function render() {
return renderToString(<App />)
}

View File

@@ -109,6 +109,29 @@ export default function Home() {
</div>
</section>
{/* Partners */}
<section className="py-16 bg-slate-50 border-t border-slate-100">
<div className="max-w-6xl mx-auto px-4 sm:px-6">
<div className="text-center mb-10">
<h2 className="text-2xl sm:text-3xl font-bold text-slate-900 mb-2">{t('partners.title')}</h2>
<p className="text-slate-500">{t('partners.subtitle')}</p>
</div>
<div className="flex flex-wrap justify-center gap-4">
{[
{ name: 'RU-CENTER', sub: 'Руцентр' },
{ name: 'REG.RU', sub: 'Регистратор доменов' },
{ name: 'МТВ', sub: 'Телекоммуникации' },
{ name: 'КОНТУР', sub: 'Электронная отчётность' },
].map(p => (
<div key={p.name} className="bg-white border border-slate-200 rounded-xl px-8 py-5 flex flex-col items-center gap-1 min-w-[160px] hover:border-blue-200 hover:shadow-sm transition-all duration-200">
<span className="text-xl font-bold text-slate-800 tracking-tight">{p.name}</span>
<span className="text-xs text-slate-400">{p.sub}</span>
</div>
))}
</div>
</div>
</section>
{/* Contact */}
<section id="contact" className="py-24 bg-slate-900">
<div className="max-w-6xl mx-auto px-4 sm:px-6">

View File

@@ -53,6 +53,10 @@ export const en = {
formSubmit: 'Send Request',
formSuccess: 'Request sent! We will contact you shortly.',
},
partners: {
title: 'Partners',
subtitle: 'We work with trusted suppliers and vendors',
},
footer: {
rights: 'All rights reserved.',
},

View File

@@ -53,6 +53,10 @@ export const ru = {
formSubmit: 'Отправить заявку',
formSuccess: 'Заявка отправлена! Мы свяжемся с вами в ближайшее время.',
},
partners: {
title: 'Партнёры',
subtitle: 'Работаем с надёжными поставщиками и вендорами',
},
footer: {
rights: 'Все права защищены.',
},