573 lines
16 KiB
Vue
573 lines
16 KiB
Vue
<script setup lang="ts">
|
||
const { locale } = useI18n()
|
||
const localePath = useLocalePath()
|
||
|
||
const isEn = computed(() => locale.value === 'en')
|
||
|
||
const heroTitle = computed(() => isEn.value
|
||
? 'Optovia makes procurement and logistics transparent'
|
||
: 'Optovia делает закупку и логистику прозрачными')
|
||
|
||
const heroSubtitle = computed(() => isEn.value
|
||
? 'One flow for product search, hubs, offers, and route decisions.'
|
||
: 'Единый поток: поиск товара, хабы, офферы и решение по маршруту.')
|
||
|
||
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.',
|
||
},
|
||
{
|
||
title: 'Hub-first route strategy',
|
||
text: 'Evaluate delivery through key hubs and optimize route economics early.',
|
||
},
|
||
{
|
||
title: 'Map-based operating control',
|
||
text: 'Keep product, destination, and route context in one place for faster execution.',
|
||
},
|
||
{
|
||
title: 'Team workflow continuity',
|
||
text: 'Share context between buyer, operations, and manager roles without data loss.',
|
||
},
|
||
]
|
||
: [
|
||
{
|
||
title: 'Поиск поставщиков и офферов',
|
||
text: 'Находите релевантных поставщиков и сравнивайте коммерцию без хаоса вкладок.',
|
||
},
|
||
{
|
||
title: 'Маршрутная стратегия через хабы',
|
||
text: 'Оценивайте доставку через ключевые хабы и заранее оптимизируйте экономику.',
|
||
},
|
||
{
|
||
title: 'Операционный контроль на карте',
|
||
text: 'Держите товар, направление и маршрут в одном месте для быстрого исполнения.',
|
||
},
|
||
{
|
||
title: 'Непрерывный командный workflow',
|
||
text: 'Передавайте контекст между закупкой, операционкой и менеджментом без потерь.',
|
||
},
|
||
])
|
||
|
||
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 = computed(() => isEn.value
|
||
? ['Agro Holdings', 'Food Retail', 'Import Teams', 'Distribution Groups', 'Regional Buyers', 'Logistics Partners']
|
||
: ['Агро холдинги', 'Пищевой ритейл', 'Импорт-команды', 'Дистрибьюторы', 'Региональные закупки', 'Логистические партнеры'])
|
||
|
||
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',
|
||
},
|
||
{
|
||
quote: 'The capsule search and hub view made supplier comparison much cleaner for our team.',
|
||
author: 'Dmitry Volkov',
|
||
role: 'Import Manager',
|
||
},
|
||
{
|
||
quote: 'Optovia removed communication noise between buyers and logistics managers.',
|
||
author: 'Alex Gromov',
|
||
role: 'CEO, Trading Company',
|
||
},
|
||
]
|
||
: [
|
||
{
|
||
quote: 'Скорость выбора маршрута сократилась с дней до часов, потому что все варианты видны на одной карте.',
|
||
author: 'Екатерина Морозова',
|
||
role: 'Руководитель закупочной операционки',
|
||
},
|
||
{
|
||
quote: 'Капсульный поиск и режим хабов сделали сравнение поставщиков заметно чище для команды.',
|
||
author: 'Дмитрий Волков',
|
||
role: 'Менеджер по импорту',
|
||
},
|
||
{
|
||
quote: 'Optovia убрала шум в коммуникации между закупкой и логистикой.',
|
||
author: 'Александр Громов',
|
||
role: 'CEO, торговая компания',
|
||
},
|
||
])
|
||
|
||
const leadTestimonial = computed(() => testimonials.value[0] ?? null)
|
||
const sideTestimonials = computed(() => testimonials.value.slice(1))
|
||
|
||
const ctaTitle = computed(() => isEn.value ? 'Scale your procurement flow with Optovia' : 'Масштабируйте поток закупок вместе с Optovia')
|
||
const ctaText = computed(() => isEn.value
|
||
? 'Move from fragmented tools to one coherent workflow.'
|
||
: 'Перейдите от разрозненных инструментов к единому рабочему контуру.')
|
||
|
||
definePageMeta({
|
||
layout: 'topnav',
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<main class="landing-page">
|
||
<section class="hero-section">
|
||
<div class="mx-auto w-full max-w-[1280px] px-3 md:px-4">
|
||
<div class="mx-auto max-w-[980px] text-center text-white">
|
||
<h1 class="text-4xl font-black leading-tight md:text-6xl">{{ heroTitle }}</h1>
|
||
<p class="mx-auto mt-5 max-w-[760px] text-base text-white/80 md:text-lg">{{ heroSubtitle }}</p>
|
||
<div class="mt-8 flex flex-wrap items-center justify-center gap-3">
|
||
<NuxtLink :to="localePath('/catalog')" class="btn h-11 min-h-0 rounded-full border-0 bg-white px-6 text-[#12213a] hover:bg-white/90">
|
||
{{ isEn ? 'Open Catalog' : 'Открыть каталог' }}
|
||
</NuxtLink>
|
||
<NuxtLink :to="localePath('/catalog')" class="btn h-11 min-h-0 rounded-full border border-white/40 bg-transparent px-6 text-white hover:bg-white/10">
|
||
{{ isEn ? 'Explore map flow' : 'Посмотреть карту' }}
|
||
</NuxtLink>
|
||
</div>
|
||
</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">
|
||
<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">
|
||
<div v-for="brand in trustedBy" :key="brand" role="listitem" class="logo-brand">{{ brand }}</div>
|
||
</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 v-if="leadTestimonial" class="review-main">
|
||
<p class="review-main__quote">«{{ leadTestimonial.quote }}»</p>
|
||
<div class="review-person">
|
||
<div class="review-avatar review-avatar--lg">{{ leadTestimonial.author.slice(0, 1) }}</div>
|
||
<div>
|
||
<p class="review-name">{{ leadTestimonial.author }}</p>
|
||
<p class="review-role">{{ leadTestimonial.role }}</p>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
|
||
<div class="review-side">
|
||
<article v-for="item in sideTestimonials" :key="item.author" class="review-mini">
|
||
<p>«{{ item.quote }}»</p>
|
||
<div class="review-person">
|
||
<div class="review-avatar">{{ item.author.slice(0, 1) }}</div>
|
||
<div>
|
||
<p class="review-name">{{ item.author }}</p>
|
||
<p class="review-role">{{ item.role }}</p>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="section section--cta">
|
||
<div class="section-inner">
|
||
<div class="cta-shell">
|
||
<h2>{{ ctaTitle }}</h2>
|
||
<p>{{ ctaText }}</p>
|
||
<NuxtLink :to="localePath('/catalog')" class="btn h-11 min-h-0 rounded-full border-0 bg-white px-6 text-[#12334f] hover:bg-white/90">
|
||
{{ isEn ? 'Start now' : 'Начать сейчас' }}
|
||
</NuxtLink>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.landing-page {
|
||
display: flex;
|
||
min-height: 100%;
|
||
flex-direction: column;
|
||
padding-bottom: 0;
|
||
background: #eef2f6;
|
||
}
|
||
|
||
.hero-section {
|
||
position: relative;
|
||
min-height: 72vh;
|
||
width: 100%;
|
||
background: linear-gradient(132deg, #0b3a46 0%, #132b49 48%, #1a2a63 100%);
|
||
padding: 10rem 0.75rem 2.5rem;
|
||
}
|
||
|
||
.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: 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;
|
||
background: linear-gradient(110deg, #10243f 0%, #1c4665 100%);
|
||
}
|
||
|
||
.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: 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-left: 1.2rem;
|
||
display: grid;
|
||
gap: 0.75rem;
|
||
color: #243e5c;
|
||
}
|
||
|
||
.section--plain {
|
||
background: #f1f4f8;
|
||
}
|
||
|
||
.logo-wall {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 0.8rem;
|
||
}
|
||
|
||
.logo-brand {
|
||
border-radius: 12px;
|
||
border: 1px solid #d3deea;
|
||
background: #fff;
|
||
padding: 0.9rem;
|
||
text-align: center;
|
||
font-weight: 700;
|
||
color: #2d4561;
|
||
}
|
||
|
||
.section--reviews {
|
||
background: #0f1f34;
|
||
}
|
||
|
||
.section--reviews .section-header h2 {
|
||
color: #fff;
|
||
}
|
||
|
||
.review-layout {
|
||
display: grid;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.review-main,
|
||
.review-mini {
|
||
border-radius: 18px;
|
||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||
background: rgba(255, 255, 255, 0.08);
|
||
padding: 1.2rem;
|
||
color: rgba(255, 255, 255, 0.9);
|
||
}
|
||
|
||
.review-main__quote {
|
||
margin: 0;
|
||
font-size: 1.18rem;
|
||
line-height: 1.55;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.review-side {
|
||
display: grid;
|
||
gap: 0.8rem;
|
||
}
|
||
|
||
.review-person {
|
||
margin-top: 1rem;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.8rem;
|
||
}
|
||
|
||
.review-avatar {
|
||
height: 2.25rem;
|
||
width: 2.25rem;
|
||
border-radius: 999px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-weight: 800;
|
||
background: rgba(255, 255, 255, 0.18);
|
||
}
|
||
|
||
.review-avatar--lg {
|
||
height: 2.75rem;
|
||
width: 2.75rem;
|
||
}
|
||
|
||
.review-name {
|
||
margin: 0;
|
||
font-weight: 700;
|
||
color: #fff;
|
||
}
|
||
|
||
.review-role {
|
||
margin: 0.2rem 0 0;
|
||
font-size: 0.86rem;
|
||
color: rgba(255, 255, 255, 0.65);
|
||
}
|
||
|
||
.section--cta {
|
||
background: #eef2f6;
|
||
}
|
||
|
||
.cta-shell {
|
||
border-radius: 24px;
|
||
padding: 2rem;
|
||
background: linear-gradient(120deg, #0f3b54 0%, #1f5b7f 100%);
|
||
color: #fff;
|
||
text-align: center;
|
||
}
|
||
|
||
.cta-shell h2 {
|
||
margin: 0;
|
||
font-size: clamp(1.8rem, 4vw, 2.8rem);
|
||
font-weight: 900;
|
||
}
|
||
|
||
.cta-shell p {
|
||
margin: 0.8rem auto 1.4rem;
|
||
max-width: 680px;
|
||
color: rgba(255, 255, 255, 0.82);
|
||
}
|
||
|
||
@media (min-width: 768px) {
|
||
.hero-section {
|
||
padding-top: 12rem;
|
||
}
|
||
|
||
.review-layout {
|
||
grid-template-columns: 1.1fr 0.9fr;
|
||
}
|
||
|
||
.logo-wall {
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
}
|
||
|
||
.why-grid {
|
||
grid-template-columns: 1fr 1fr;
|
||
align-items: start;
|
||
}
|
||
}
|
||
|
||
@media (min-width: 1024px) {
|
||
.logo-wall {
|
||
grid-template-columns: repeat(6, minmax(0, 1fr));
|
||
}
|
||
}
|
||
</style>
|