627 lines
17 KiB
Vue
627 lines
17 KiB
Vue
<script setup lang="ts">
|
||
const { locale } = useI18n()
|
||
|
||
const isEn = computed(() => locale.value === 'en')
|
||
|
||
const heroTitle = computed(() => isEn.value
|
||
? 'Optovia makes procurement and logistics transparent'
|
||
: 'Optovia делает закупку и логистику прозрачными')
|
||
|
||
const howSteps = computed(() => isEn.value
|
||
? [
|
||
{
|
||
number: '01',
|
||
title: 'Choose product and destination',
|
||
text: 'Start from the top search capsule and set what you buy and where it should go.',
|
||
},
|
||
{
|
||
number: '02',
|
||
title: 'See offers and hubs on map',
|
||
text: 'Compare suppliers, hubs, prices, and route options on one interactive canvas.',
|
||
},
|
||
{
|
||
number: '03',
|
||
title: 'Commit with full context',
|
||
text: 'Move to the best option with clear terms, timeline, and next actions for your team.',
|
||
},
|
||
]
|
||
: [
|
||
{
|
||
number: '01',
|
||
title: 'Выберите товар и направление',
|
||
text: 'Начните в верхней поисковой капсуле: задайте что закупаете и куда везете.',
|
||
},
|
||
{
|
||
number: '02',
|
||
title: 'Смотрите офферы и хабы на карте',
|
||
text: 'Сравнивайте поставщиков, хабы, цены и маршруты в одном интерактивном полотне.',
|
||
},
|
||
{
|
||
number: '03',
|
||
title: 'Принимайте решение с полным контекстом',
|
||
text: 'Переходите к лучшему варианту с понятными условиями, сроками и шагами для команды.',
|
||
},
|
||
])
|
||
|
||
const services = computed(() => isEn.value
|
||
? [
|
||
{
|
||
title: 'Supplier and offer discovery',
|
||
text: 'Find relevant suppliers and compare live commercial terms without tab chaos.',
|
||
toneFrom: '#0f243d',
|
||
toneTo: '#153962',
|
||
},
|
||
{
|
||
title: 'Hub-first route strategy',
|
||
text: 'Evaluate delivery through key hubs and optimize route economics early.',
|
||
toneFrom: '#182b45',
|
||
toneTo: '#22466f',
|
||
},
|
||
{
|
||
title: 'Map-based operating control',
|
||
text: 'Keep product, destination, and route context in one place for faster execution.',
|
||
toneFrom: '#15243a',
|
||
toneTo: '#214a60',
|
||
},
|
||
{
|
||
title: 'Team workflow continuity',
|
||
text: 'Share context between buyer, operations, and manager roles without data loss.',
|
||
toneFrom: '#122033',
|
||
toneTo: '#1d3a5c',
|
||
},
|
||
]
|
||
: [
|
||
{
|
||
title: 'Поиск поставщиков и офферов',
|
||
text: 'Находите релевантных поставщиков и сравнивайте коммерцию без хаоса вкладок.',
|
||
toneFrom: '#0f243d',
|
||
toneTo: '#153962',
|
||
},
|
||
{
|
||
title: 'Маршрутная стратегия через хабы',
|
||
text: 'Оценивайте доставку через ключевые хабы и заранее оптимизируйте экономику.',
|
||
toneFrom: '#182b45',
|
||
toneTo: '#22466f',
|
||
},
|
||
{
|
||
title: 'Операционный контроль на карте',
|
||
text: 'Держите товар, направление и маршрут в одном месте для быстрого исполнения.',
|
||
toneFrom: '#15243a',
|
||
toneTo: '#214a60',
|
||
},
|
||
{
|
||
title: 'Непрерывный командный workflow',
|
||
text: 'Передавайте контекст между закупкой, операционкой и менеджментом без потерь.',
|
||
toneFrom: '#122033',
|
||
toneTo: '#1d3a5c',
|
||
},
|
||
])
|
||
|
||
const advantages = computed(() => isEn.value
|
||
? [
|
||
'Single visual language from homepage to map and cabinet.',
|
||
'Faster decisions due to shared context between roles.',
|
||
'Less operational friction in procurement and route planning.',
|
||
]
|
||
: [
|
||
'Единый визуальный контур от лендинга до карты и кабинета.',
|
||
'Быстрее решения за счет общего контекста между ролями.',
|
||
'Меньше операционных потерь в закупке и планировании маршрута.',
|
||
])
|
||
|
||
const trustedBy = [
|
||
{ name: 'Gazprom', logo: '/trust-logos/gazprom.svg' },
|
||
{ name: 'Rossiya 1', logo: '/trust-logos/russia1.svg' },
|
||
{ name: 'Absolut Bank', logo: '/trust-logos/absolutbank.svg' },
|
||
{ name: 'Kalashnikov', logo: '/trust-logos/kalashnikov.svg' },
|
||
{ name: 'Sber Logistics', logo: '/trust-logos/sberlog.svg' },
|
||
{ name: 'Dellin', logo: '/trust-logos/dellin.svg' },
|
||
{ name: 'PEK', logo: '/trust-logos/pek.svg' },
|
||
{ name: 'FESCO', logo: '/trust-logos/fesco.svg' },
|
||
] as const
|
||
|
||
const testimonials = computed(() => isEn.value
|
||
? [
|
||
{
|
||
quote: 'We reduced route decision time from days to hours because all options are visible on one map.',
|
||
author: 'Elena Morozova',
|
||
role: 'Head of Procurement Operations',
|
||
avatar: 'https://randomuser.me/api/portraits/women/44.jpg',
|
||
},
|
||
{
|
||
quote: 'The capsule search and hub view made supplier comparison much cleaner for our team.',
|
||
author: 'Dmitry Volkov',
|
||
role: 'Import Manager',
|
||
avatar: 'https://randomuser.me/api/portraits/men/52.jpg',
|
||
},
|
||
{
|
||
quote: 'Optovia removed communication noise between buyers and logistics managers.',
|
||
author: 'Alex Gromov',
|
||
role: 'CEO, Trading Company',
|
||
avatar: 'https://randomuser.me/api/portraits/men/41.jpg',
|
||
},
|
||
]
|
||
: [
|
||
{
|
||
quote: 'Скорость выбора маршрута сократилась с дней до часов, потому что все варианты видны на одной карте.',
|
||
author: 'Екатерина Морозова',
|
||
role: 'Руководитель закупочной операционки',
|
||
avatar: 'https://randomuser.me/api/portraits/women/44.jpg',
|
||
},
|
||
{
|
||
quote: 'Капсульный поиск и режим хабов сделали сравнение поставщиков заметно чище для команды.',
|
||
author: 'Дмитрий Волков',
|
||
role: 'Менеджер по импорту',
|
||
avatar: 'https://randomuser.me/api/portraits/men/52.jpg',
|
||
},
|
||
{
|
||
quote: 'Optovia убрала шум в коммуникации между закупкой и логистикой.',
|
||
author: 'Александр Громов',
|
||
role: 'CEO, торговая компания',
|
||
avatar: 'https://randomuser.me/api/portraits/men/41.jpg',
|
||
},
|
||
])
|
||
|
||
definePageMeta({
|
||
layout: 'topnav',
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<main class="landing-page">
|
||
<section class="relative min-h-[72vh] w-full bg-gradient-to-br from-[#0b3a46] via-[#132b49] to-[#1a2a63] px-3 pb-10 pt-40 text-white md:px-4 md:pt-52">
|
||
<div class="mx-auto w-full max-w-[1280px]">
|
||
<div class="mx-auto max-w-[940px] text-center" data-landing-search-anchor>
|
||
<h1 class="text-4xl font-black leading-tight md:text-6xl">
|
||
{{ heroTitle }}
|
||
</h1>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="section section--light">
|
||
<div class="section-inner">
|
||
<header class="section-header">
|
||
<h2>{{ isEn ? 'How it works' : 'Как это работает' }}</h2>
|
||
</header>
|
||
|
||
<ol class="steps-flow">
|
||
<li v-for="step in howSteps" :key="step.number" class="step-item">
|
||
<p class="step-number">{{ step.number }}</p>
|
||
<h3>{{ step.title }}</h3>
|
||
<p>{{ step.text }}</p>
|
||
</li>
|
||
</ol>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="section section--dark">
|
||
<div class="section-inner">
|
||
<header class="section-header section-header--inverse">
|
||
<h2>{{ isEn ? 'Core capabilities' : 'Ключевые возможности' }}</h2>
|
||
</header>
|
||
|
||
<div class="service-stack">
|
||
<article
|
||
v-for="(service, index) in services"
|
||
:key="service.title"
|
||
class="service-lane"
|
||
:style="{ backgroundImage: `linear-gradient(110deg, ${service.toneFrom} 0%, ${service.toneTo} 100%)` }"
|
||
>
|
||
<p class="service-index">{{ String(index + 1).padStart(2, '0') }}</p>
|
||
<div>
|
||
<h3>{{ service.title }}</h3>
|
||
<p>{{ service.text }}</p>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="section section--accent">
|
||
<div class="section-inner why-grid">
|
||
<div>
|
||
<h2>{{ isEn ? 'Why teams choose this model' : 'Почему команды выбирают эту модель' }}</h2>
|
||
<p class="why-lead">
|
||
{{ isEn ? 'The same interaction model works from landing entry to day-to-day map operations.' : 'Одна и та же модель взаимодействия работает от первого экрана до ежедневной работы на карте.' }}
|
||
</p>
|
||
</div>
|
||
|
||
<ul class="why-list">
|
||
<li v-for="item in advantages" :key="item">{{ item }}</li>
|
||
</ul>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="section section--plain">
|
||
<div class="section-inner">
|
||
<header class="section-header">
|
||
<h2>{{ isEn ? 'Trusted by teams' : 'Нам доверяют команды' }}</h2>
|
||
</header>
|
||
|
||
<div class="logo-wall" role="list" :aria-label="isEn ? 'Client logos' : 'Логотипы клиентов'">
|
||
<figure v-for="brand in trustedBy" :key="brand.name" role="listitem" class="logo-brand">
|
||
<img :src="brand.logo" :alt="`Logo ${brand.name}`" loading="lazy" />
|
||
</figure>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="section section--reviews">
|
||
<div class="section-inner">
|
||
<header class="section-header">
|
||
<h2>{{ isEn ? 'What teams say' : 'Что говорят команды' }}</h2>
|
||
</header>
|
||
|
||
<div class="review-layout">
|
||
<article class="review-main">
|
||
<div class="review-person">
|
||
<img :src="testimonials[0].avatar" :alt="testimonials[0].author" class="review-avatar review-avatar--lg" loading="lazy" />
|
||
<div>
|
||
<p class="review-name">{{ testimonials[0].author }}</p>
|
||
<p class="review-role">{{ testimonials[0].role }}</p>
|
||
</div>
|
||
</div>
|
||
<p class="review-main__quote">«{{ testimonials[0].quote }}»</p>
|
||
</article>
|
||
|
||
<div class="review-side">
|
||
<article v-for="item in testimonials.slice(1)" :key="item.author" class="review-mini">
|
||
<div class="review-person">
|
||
<img :src="item.avatar" :alt="item.author" class="review-avatar" loading="lazy" />
|
||
<div>
|
||
<p class="review-name">{{ item.author }}</p>
|
||
<p class="review-role">{{ item.role }}</p>
|
||
</div>
|
||
</div>
|
||
<p>«{{ item.quote }}»</p>
|
||
</article>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.landing-page {
|
||
display: flex;
|
||
min-height: 100%;
|
||
flex-direction: column;
|
||
padding-bottom: 0;
|
||
background: #eef2f6;
|
||
}
|
||
|
||
.section {
|
||
padding: 3.25rem 0;
|
||
}
|
||
|
||
.section-inner {
|
||
margin: 0 auto;
|
||
width: 100%;
|
||
max-width: 1280px;
|
||
padding: 0 0.75rem;
|
||
}
|
||
|
||
.section-header {
|
||
margin-bottom: 1.35rem;
|
||
}
|
||
|
||
.section-header h2 {
|
||
margin: 0.3rem 0 0;
|
||
font-size: clamp(1.8rem, 4vw, 3rem);
|
||
font-weight: 900;
|
||
color: #12213a;
|
||
}
|
||
|
||
.section-header--inverse h2 {
|
||
color: #fff;
|
||
}
|
||
|
||
.section--light {
|
||
background: linear-gradient(180deg, #f1f5fb 0%, #edf3fb 100%);
|
||
}
|
||
|
||
.steps-flow {
|
||
margin: 0;
|
||
padding: 0;
|
||
list-style: none;
|
||
display: grid;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.step-item {
|
||
position: relative;
|
||
padding: 1.2rem 0 1.2rem 4.3rem;
|
||
border-top: 1px solid #cfdae8;
|
||
}
|
||
|
||
.step-number {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0.65rem;
|
||
margin: 0;
|
||
font-size: clamp(1.8rem, 4vw, 2.7rem);
|
||
font-weight: 900;
|
||
color: #d12e35;
|
||
}
|
||
|
||
.step-item h3 {
|
||
margin: 0;
|
||
font-size: 1.35rem;
|
||
font-weight: 900;
|
||
color: #12213a;
|
||
}
|
||
|
||
.step-item p {
|
||
margin: 0.45rem 0 0;
|
||
color: #3f5673;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.section--dark {
|
||
background:
|
||
radial-gradient(circle at 90% 15%, rgba(217, 61, 67, 0.3), rgba(217, 61, 67, 0) 34%),
|
||
linear-gradient(155deg, #0b1a2f 0%, #102842 100%);
|
||
}
|
||
|
||
.service-stack {
|
||
display: grid;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.service-lane {
|
||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||
border-radius: 18px;
|
||
padding: 1.15rem;
|
||
display: grid;
|
||
gap: 0.8rem;
|
||
grid-template-columns: auto 1fr;
|
||
align-items: start;
|
||
color: #fff;
|
||
}
|
||
|
||
.service-index {
|
||
margin: 0;
|
||
font-size: 1.15rem;
|
||
font-weight: 900;
|
||
color: rgba(255, 255, 255, 0.7);
|
||
}
|
||
|
||
.service-lane h3 {
|
||
margin: 0;
|
||
font-size: 1.28rem;
|
||
font-weight: 900;
|
||
}
|
||
|
||
.service-lane p {
|
||
margin: 0.45rem 0 0;
|
||
color: rgba(255, 255, 255, 0.88);
|
||
}
|
||
|
||
.section--accent {
|
||
background:
|
||
radial-gradient(circle at 6% 0%, rgba(251, 220, 207, 0.54), rgba(251, 220, 207, 0) 37%),
|
||
linear-gradient(180deg, #f8f0ea 0%, #f4ece8 100%);
|
||
}
|
||
|
||
.why-grid {
|
||
display: grid;
|
||
gap: 1.35rem;
|
||
}
|
||
|
||
.why-grid h2 {
|
||
margin: 0.3rem 0 0;
|
||
font-size: clamp(1.8rem, 4vw, 3rem);
|
||
font-weight: 900;
|
||
color: #12213a;
|
||
}
|
||
|
||
.why-lead {
|
||
margin: 1rem 0 0;
|
||
color: #3f5673;
|
||
line-height: 1.55;
|
||
}
|
||
|
||
.why-list {
|
||
margin: 0;
|
||
padding: 0;
|
||
list-style: none;
|
||
display: grid;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.why-list li {
|
||
padding: 0.2rem 0 0.2rem 2.3rem;
|
||
color: #1d2f49;
|
||
font-weight: 700;
|
||
position: relative;
|
||
line-height: 1.45;
|
||
}
|
||
|
||
.why-list li::before {
|
||
content: '✓';
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0.05rem;
|
||
width: 1.55rem;
|
||
height: 1.55rem;
|
||
border-radius: 999px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: #1f8a5a;
|
||
color: #fff;
|
||
font-size: 0.9rem;
|
||
font-weight: 900;
|
||
}
|
||
|
||
.section--plain {
|
||
background: #f7f9fc;
|
||
}
|
||
|
||
.logo-wall {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 0.8rem;
|
||
}
|
||
|
||
.logo-brand {
|
||
margin: 0;
|
||
min-height: 84px;
|
||
border-radius: 20px;
|
||
border: 1px solid #d4dde8;
|
||
background: linear-gradient(180deg, #ffffff 0%, #f2f6fb 100%);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 0.75rem;
|
||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9);
|
||
}
|
||
|
||
.logo-brand img {
|
||
width: min(88%, 240px);
|
||
height: auto;
|
||
object-fit: contain;
|
||
}
|
||
|
||
.section--reviews {
|
||
background: linear-gradient(180deg, #edf3fb 0%, #e9f0f8 100%);
|
||
flex: 1 0 auto;
|
||
padding-bottom: 0;
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.review-layout {
|
||
display: grid;
|
||
gap: 0.8rem;
|
||
}
|
||
|
||
.review-main {
|
||
border-radius: 24px;
|
||
padding: 1.3rem;
|
||
background: linear-gradient(145deg, #14253d 0%, #1c3b5e 100%);
|
||
color: #fff;
|
||
display: grid;
|
||
align-content: start;
|
||
gap: 0.9rem;
|
||
}
|
||
|
||
.review-person {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.review-avatar {
|
||
width: 2.75rem;
|
||
height: 2.75rem;
|
||
border-radius: 999px;
|
||
object-fit: cover;
|
||
border: 2px solid rgba(255, 255, 255, 0.44);
|
||
}
|
||
|
||
.review-avatar--lg {
|
||
width: 3.2rem;
|
||
height: 3.2rem;
|
||
}
|
||
|
||
.review-name {
|
||
margin: 0;
|
||
font-size: 0.95rem;
|
||
font-weight: 800;
|
||
color: #ffffff;
|
||
}
|
||
|
||
.review-role {
|
||
margin: 0.1rem 0 0;
|
||
font-size: 0.8rem;
|
||
color: rgba(255, 255, 255, 0.82);
|
||
}
|
||
|
||
.review-main__quote {
|
||
margin: 0;
|
||
color: #fff;
|
||
font-size: clamp(1.2rem, 2.6vw, 1.6rem);
|
||
line-height: 1.45;
|
||
}
|
||
|
||
.review-side {
|
||
display: grid;
|
||
gap: 0.8rem;
|
||
}
|
||
|
||
.review-mini {
|
||
border-left: 4px solid #d12e35;
|
||
padding: 0.75rem 0.9rem;
|
||
background: rgba(255, 255, 255, 0.65);
|
||
}
|
||
|
||
.review-mini > p {
|
||
margin: 0.55rem 0 0;
|
||
color: #27405f;
|
||
}
|
||
|
||
.review-mini .review-name {
|
||
color: #1e3555;
|
||
}
|
||
|
||
.review-mini .review-role {
|
||
color: #4f6581;
|
||
}
|
||
|
||
@media (min-width: 768px) {
|
||
.section {
|
||
padding: 4.5rem 0;
|
||
}
|
||
|
||
.section-inner {
|
||
padding: 0 1rem;
|
||
}
|
||
|
||
.steps-flow {
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
gap: 1.5rem;
|
||
}
|
||
|
||
.step-item {
|
||
border-top: 0;
|
||
border-left: 1px solid #cfdae8;
|
||
padding: 1rem 0 1rem 1.7rem;
|
||
}
|
||
|
||
.step-number {
|
||
position: static;
|
||
margin-bottom: 0.75rem;
|
||
}
|
||
|
||
.why-grid {
|
||
grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
|
||
align-items: start;
|
||
}
|
||
|
||
.why-list {
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
align-items: stretch;
|
||
gap: 1.35rem;
|
||
}
|
||
|
||
.logo-wall {
|
||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||
gap: 1rem 1.2rem;
|
||
}
|
||
|
||
.review-layout {
|
||
grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
|
||
gap: 1.2rem;
|
||
}
|
||
|
||
}
|
||
|
||
@media (max-width: 1023px) {
|
||
.landing-page {
|
||
padding-bottom: 0;
|
||
}
|
||
}
|
||
</style>
|