Compare commits
4 Commits
4d01a65859
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| acf929ed8c | |||
| 8ebc42dd09 | |||
| c4e5a532a1 | |||
| 913b66a9cb |
+11
-1
@@ -15,6 +15,11 @@ RUN npm run build
|
||||
# =====================================================
|
||||
FROM node:20-alpine AS backend-build
|
||||
|
||||
# bcrypt — нативный модуль. Готовый бинарник с github внутри сборки не
|
||||
# скачивается (запрос к release-assets обрывается), поэтому собираем из
|
||||
# исходников: для этого нужны python3/make/g++.
|
||||
RUN apk add --no-cache python3 make g++
|
||||
|
||||
WORKDIR /app/backend
|
||||
COPY backend/package.json backend/package-lock.json* ./
|
||||
RUN npm install
|
||||
@@ -33,7 +38,12 @@ WORKDIR /app
|
||||
|
||||
# Backend production deps
|
||||
COPY backend/package.json backend/package-lock.json* ./backend/
|
||||
RUN cd backend && npm install --omit=dev
|
||||
# То же самое для боевых зависимостей: компилятор ставим временно и сносим
|
||||
# сразу после установки, чтобы не тащить его в итоговый образ.
|
||||
RUN apk add --no-cache --virtual .build-deps python3 make g++ \
|
||||
&& cd backend && npm install --omit=dev \
|
||||
&& apk del .build-deps \
|
||||
&& rm -rf /root/.cache
|
||||
|
||||
# Built backend
|
||||
COPY --from=backend-build /app/backend/dist ./backend/dist
|
||||
|
||||
+3
-3
@@ -10,9 +10,9 @@
|
||||
<meta property="og:description" content="Технологии, которые решают реальные задачи" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://umbyte.ru" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
||||
<!-- ШРИФТЫ ЛОКАЛЬНЫЕ: раньше тянулись с fonts.googleapis.com и при
|
||||
ограничениях доступа не приезжали. Подмножества cyrillic+latin. -->
|
||||
<link href="/fonts/fonts.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,198 @@
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Inter-400-cyrillic.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Inter-400-latin.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Inter-500-cyrillic.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Inter-500-latin.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Inter-600-cyrillic.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Inter-600-latin.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Inter-700-cyrillic.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Inter-700-latin.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Onest';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Onest-400-cyrillic.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Onest';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Onest-400-latin.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Onest';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Onest-500-cyrillic.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Onest';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Onest-500-latin.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Onest';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Onest-600-cyrillic.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Onest';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Onest-600-latin.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Unbounded';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Unbounded-400-cyrillic.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Unbounded';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Unbounded-400-latin.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Unbounded';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Unbounded-500-cyrillic.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Unbounded';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Unbounded-500-latin.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Unbounded';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Unbounded-600-cyrillic.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Unbounded';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Unbounded-600-latin.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Unbounded';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Unbounded-700-cyrillic.woff2) format('woff2');
|
||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Unbounded';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Unbounded-700-latin.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
@@ -176,7 +176,7 @@ export function CardPage() {
|
||||
}
|
||||
|
||||
const cardCss = `
|
||||
@import url('https://fonts.googleapis.com/css2?family=Unbounded:wght@400;500;600;700&family=Onest:wght@400;500;600&display=swap');
|
||||
@import url('/fonts/fonts.css');
|
||||
.cardpage{--bg:#E9EDF7;--bg2:#DDE3F2;--card:#FFFFFF;--card2:#FBFCFF;--ink:#15132E;--ink2:#5C5984;--line:#E7E9F4;--indigo:#312E81;--indigo2:#4F4BC4;--cyan:#06B6D4;--cyan-glow:#22D3EE;--violet:#7C5CFF;--shadow:0 30px 70px -24px rgba(49,46,129,.32),0 10px 30px -18px rgba(6,182,212,.28);
|
||||
font-family:'Onest',sans-serif;color:var(--ink);min-height:100vh;display:flex;align-items:center;justify-content:center;padding:30px 18px;position:relative;overflow:hidden;perspective:1200px;background:linear-gradient(165deg,var(--bg),var(--bg2))}
|
||||
@media (prefers-color-scheme:dark){.cardpage{--bg:#0C0B22;--bg2:#141233;--card:#17163a;--card2:#1c1a44;--ink:#F4F4FF;--ink2:#A6A3D9;--line:rgba(255,255,255,.12);--indigo:#4F4BC4;--indigo2:#6A66E0;--cyan:#22D3EE;--cyan-glow:#67E8F9;--shadow:0 30px 80px -24px rgba(0,0,0,.7),0 0 40px -10px rgba(34,211,238,.25)}}
|
||||
|
||||
@@ -18,10 +18,12 @@ const UI: Record<Lang, Record<string, string>> = {
|
||||
ru: {
|
||||
products: 'Продукты', approach: 'Подход', contacts: 'Контакты',
|
||||
discuss: 'Обсудить проект', director: 'Генеральный директор',
|
||||
inn: 'ИНН', kpp: 'КПП', ogrn: 'ОГРН', region: 'Россия',
|
||||
},
|
||||
en: {
|
||||
products: 'Products', approach: 'Approach', contacts: 'Contacts',
|
||||
discuss: 'Discuss a project', director: 'CEO',
|
||||
inn: 'INN', kpp: 'KPP', ogrn: 'OGRN', region: 'Russia',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -182,7 +184,8 @@ export function Landing() {
|
||||
{Array.isArray(hero?.stats) && hero.stats.length > 0 && (
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mt-14 pt-7 border-t border-slate-200">
|
||||
{hero.stats.map((stat: any, idx: number) => {
|
||||
const isProd = typeof stat.label === 'string' && stat.label.toUpperCase().includes('ПРОДУКТ');
|
||||
// Подменяем только счётчик продуктов (число), а не любую подпись со словом «продукт»
|
||||
const isProd = typeof stat.label === 'string' && /^\d+$/.test(String(stat.value).trim()) && stat.label.toUpperCase().includes('ПРОДУКТ');
|
||||
const value = isProd ? String(productCount) : stat.value;
|
||||
const label = isProd ? pluralProducts(productCount) : stat.label;
|
||||
return (
|
||||
@@ -344,9 +347,9 @@ export function Landing() {
|
||||
<div className="text-xs text-slate-500 leading-relaxed mb-5 pb-5 border-b border-slate-200">
|
||||
<div className="text-slate-600 font-medium mb-1">{(lang === 'en' && settings.company_name_en) || settings.company_name_full || 'ООО «Умный Байт»'}</div>
|
||||
<div className="flex flex-wrap gap-x-4 gap-y-1">
|
||||
{settings.company_inn && <span>ИНН {settings.company_inn}</span>}
|
||||
{settings.company_kpp && <span>КПП {settings.company_kpp}</span>}
|
||||
{settings.company_ogrn && <span>ОГРН {settings.company_ogrn}</span>}
|
||||
{settings.company_inn && <span>{t('inn')} {settings.company_inn}</span>}
|
||||
{settings.company_kpp && <span>{t('kpp')} {settings.company_kpp}</span>}
|
||||
{settings.company_ogrn && <span>{t('ogrn')} {settings.company_ogrn}</span>}
|
||||
</div>
|
||||
{(settings.company_address || settings.company_address_en) && (
|
||||
<div className="mt-1">{(lang === 'en' && settings.company_address_en) || settings.company_address}</div>
|
||||
@@ -372,7 +375,7 @@ export function Landing() {
|
||||
<Logo size={20} />
|
||||
<span className="text-xs text-slate-600">© {new Date().getFullYear()} {(lang === 'en' && settings.company_name_en) || settings.company_name_full || 'ООО «Умный Байт»'}</span>
|
||||
</div>
|
||||
<div className="text-xs text-slate-500">{settings.domain || 'umbyte.ru'} · {settings.region || 'Россия'}</div>
|
||||
<div className="text-xs text-slate-500">{settings.domain || 'umbyte.ru'} · {(lang === 'en' ? settings.region_en : settings.region) || t('region')}</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
Reference in New Issue
Block a user