update landing
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2025-08-20 13:19:32 +03:00
parent 4771b374ac
commit c84b9788d9
15 changed files with 238 additions and 309 deletions

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

BIN
public/img/samolet.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 MiB

View File

@@ -7,25 +7,35 @@
<q-list separator>
<q-expansion-item
group="FAQgroup"
v-for="item in 5"
v-for="item in 8"
:key="item"
switch-toggle-side
header-class="text-h5"
header-class="text-h6"
expand-icon="mdi-plus"
expanded-icon="mdi-close"
expand-icon-class="text-brand2"
class="fix-icon-color"
>
<template #header="{ expanded }">
<div :class="expanded ? 'text-brand' : ''" class="w100">
<div :class="expanded ? 'text-primary' : ''" class="w100">
{{ $t('faq__question_' + item) }}
</div>
</template>
<q-card>
<q-card-section class="text-h6">
<q-card-section class="text-grey-8">
{{ $t('faq__answer_' + item) }}
</q-card-section>
</q-card>
</q-expansion-item>
</q-list>
<div class="text-h6 text-primary q-py-md" align="center">
{{ $t('faq__description') }}
<a
href="mailto:a-mart@ya.ru"
style="text-decoration: none; color: inherit"
>
a-mart@ya.ru
</a>
</div>
</div>
</slide-template>
</template>
@@ -35,11 +45,10 @@
</script>
<style scoped>
.custom-expansion.q-expansion-item--collapsed :deep(.q-item__section--side .q-icon) {
transition: transform 0.3s;
}
.custom-expansion.q-expansion-item--expanded :deep(.q-item__section--side .q-icon) {
transform: rotate(180deg);
}
<style scoped lang="scss">
.q-expansion-item--expanded.fix-icon-color:deep(i) {
color: $primary;
transition: transform 0.3s ease;
transform: rotate(45deg);
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<div class="w100 flex justify-between bg-grey-11 text-caption q-pa-md q-gutter-md">
<div class="w100 flex justify-between bg-grey-11 text-caption q-pa-md q-gutter-y-md">
<div class="flex column col-12 col-sm">
<base-logo class="text-body1 q-pb-sm"/>
<div class="flex items-center">

View File

@@ -1,19 +1,16 @@
<template>
<div
class="flex w100 q-pa-lg text-white relative-position"
:class="!isAlignTop ? 'justify-center' : 'justify-around vert-height'"
class="flex w100 text-white relative-position vert-height"
:class="isAlignTop ? 'justify-center' : 'justify-end'"
style="background-image: url('/img/samolet.jpg'); background-size: cover; height: 100vh;"
>
<svg v-if ="isAlignTop" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="none">
<polygon fill="white" points="0,0 55,0 45,101 0,101"/>
</svg>
<mesh-background v-if ="isAlignTop" style="z-index: -2"/>
<div
ref="slogan"
class="flex items-center"
>
<div
class="flex column justify-center q-pa-lg q-ma-lg q-gutter-y-md no-wrap bg-transperant"
style="max-width: 400px; "
class="flex bg-white column justify-center q-pa-lg q-ma-lg q-gutter-y-md no-wrap bg-transperant"
style="max-width: 400px; border-radius: 12px; opacity: 0.8"
:style="!isAlignTop ? 'text-align : center' : ''"
>
<div class="text-h5 text-grey">
@@ -41,25 +38,12 @@
</div>
</div>
</div>
<div
ref="image"
class="text-red flex"
>
<img
src="/img/1.png"
class="q-ma-lg"
style="object-fit: scale-down;"
/>
</div>
<q-resize-observer @resize="checkAlign"/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import meshBackground from 'components/meshBackground.vue'
const slogan = ref(null)
const image = ref(null)

View File

@@ -1,76 +1,103 @@
<template>
<slide-template title="price__title">
<q-card
class="flex column justify-center q-my-md items-center q-gutter-y-md"
style="max-width: 400px"
>
<div class="flex column items-center">
<div class="flex text-h6">
<telegram-star color="gold" size="24px"/>
<span class="q-ml-sm" style="text-decoration: line-through;">2</span>&nbsp;
<span class="text-bold text-red">0</span>&nbsp;
<span>- {{ $t('price__chat_per_day') }}</span>
<div ref="container" class="w100 flex no-wrap">
<q-resize-observer @resize="updateWidth" />
<div class="w100 flex justify-center" v-if="containerWidth > 800">
<q-card
v-for="(item, idx) in tariff"
:key="idx"
class="q-pa-md q-ma-sm flex items-center column"
style="width: 20%"
>
<price-section-item
:name="item.name"
:chats-qty="item.chatsQty"
:price="item.price"
/>
</q-card>
</div>
<div class="flex items-center">
<q-badge color="red" class="q-mr-sm">100% OFF</q-badge>
<span>{{ $t('price__sale_date') }}</span>
</div>
</div>
<q-card
flat
class="bg-grey-3"
style="border-radius: 12px;"
>
<q-item>
<q-item-section avatar>
<telegram-star color="gold" size="48px"/>
</q-item-section>
<q-item-section>
<q-item-label class="text-grey">
{{ $t('price__stars_pay') }}
</q-item-label>
<q-item-label class="text-h6">
Telegram Stars
</q-item-label>
<q-item-label class="text-grey">
{{ $t('price__stars_description') }}
</q-item-label>
</q-item-section>
</q-item>
</q-card>
<q-list class="q-my-none q-pa-md">
<q-item
v-for="item in priceItems"
:key="item.id"
dense
<q-carousel
v-else
v-model="slide"
transition-prev="scale"
transition-next="scale"
swipeable
animated
navigation
padding
height="225px"
control-color="primary"
class="w100"
>
<q-item-section avatar>
<q-avatar text-color="brand2">
<q-icon v-if="item.icon" :name="item.icon" size="md"/>
<span v-else class="text-bold">{{ item.text }}</span>
</q-avatar>
</q-item-section>
<q-item-section>
{{ $t(item.label)}}
</q-item-section>
</q-item>
</q-list>
<q-carousel-slide
v-for="(item, idx) in tariff"
:key="idx"
:name="item.name"
class="flex justify-center q-pt-lmdq-pa-none q-ma-none"
>
<price-section-item
:name="item.name"
:chats-qty="item.chatsQty"
:price="item.price"
/>
</q-carousel-slide>
</q-carousel>
</div>
<div class="q-ma-md" align="center" style="max-width: 60%;">
{{ $t('price__tariff_description') }}
</div>
<q-card
flat
class="bg-grey-3"
style="border-radius: 12px;"
>
<q-item>
<q-item-section avatar>
<telegram-star color="gold" size="48px"/>
</q-item-section>
<q-item-section>
<q-item-label class="text-grey">
{{ $t('price__stars_pay') }}
</q-item-label>
<q-item-label class="text-h6">
Telegram Stars
</q-item-label>
<q-item-label class="text-grey">
{{ $t('price__stars_description') }}
</q-item-label>
</q-item-section>
</q-item>
</q-card>
</slide-template>
</slide-template>
</template>
<script setup lang="ts">
import telegramStar from 'components/TelegramStar.vue'
import { ref } from 'vue'
import SlideTemplate from 'components/SlideTemplate.vue'
import PriceSectionItem from 'components/PriceSectionItem.vue'
import telegramStar from 'components/TelegramStar.vue'
const priceItems = [
{ id: 1, icon: 'mdi-all-inclusive', label: 'price_unlimited_users' },
{ id: 2, icon: 'mdi-all-inclusive', label: 'price_unlimited_projects' },
{ id: 3, text: '5', label: 'price_free_chats' },
{ id: 4, icon: 'mdi-lifebuoy', label: 'price_support' }
const tariff = [
{ id: 1, name: 'TEST', price: null, chatsQty: 5 },
{ id: 2, name: 'START', price: 1000, chatsQty: 15 },
{ id: 3, name: 'PRO', price: 5000, chatsQty: 40 },
{ id: 4, name: 'VIP', price: 12000, chatsQty: null }
]
const containerWidth = ref(0)
const cardWidth=ref(175)
const updateWidth = ({ width }) => {
containerWidth.value = width
cardWidth.value = width < 1200 ? 250 : 175
}
const slide = ref(tariff[0].name)
</script>

View File

@@ -0,0 +1,42 @@
<template>
<div class="flex column items-center">
<div class="text-h5 text-primary text-bold">
{{ name }}
</div>
<div class="flex items-center" style="min-height: 50px;">
<div v-if="price" class="flex column items-center">
<div class="flex no-wrap items-center">
<telegram-star color="gold" size="24px" class="q-mr-xs"/>
<span class="text-h4">{{ price }}</span>
</div>
<span class="text-caption">{{ $t('price__per_month') }}</span>
</div>
<div v-else class="text-bold text-h5">
{{ $t('price__free_tax') }}
</div>
</div>
<div class="flex items-center q-pt-md" style="min-height: 50px;">
<div class="flex no-wrap items-center">
<span v-if="chatsQty" class="text-brand2 text-bold text-h5">
{{ chatsQty }}
</span>
<q-icon v-else name="mdi-all-inclusive" size="md" color="brand2"/>
<span class="q-pl-sm">
{{ $t('price__chats')}}
</span>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import telegramStar from 'components/TelegramStar.vue'
defineProps({
name: String,
price: Number,
chatsQty: Number
})
</script>

View File

@@ -1,87 +1,77 @@
<template>
<slide-template title="problem__title">
<div ref="container" class="w100">
<slide-template>
<div ref="container" class="w100 flex no-wrap q-pt-lg">
<q-resize-observer @resize="updateWidth" />
<div
v-for="(row, rowIndex) in rows"
:key="rowIndex"
class="row q-py-none"
:class="rowClass(row.length)"
>
<div
v-for="(item, itemIndex) in row"
:key="itemIndex"
class="flex-item"
:style="itemStyle(row.length)"
<div class="w100 flex justify-center" v-if="containerWidth > 800">
<q-card
v-for="(item, idx) in problems"
:key="idx"
class="q-pa-md q-ma-sm"
>
<problem-section-item
:icon="item.icon"
:title="item.title"
:description="item.description"
style="overflow: hidden; min-width: 200px; max-width: 100%"
style="overflow: hidden;"
:style="{ width: cardWidth + 'px' }"
/>
</div>
</q-card>
</div>
<q-carousel
v-else
v-model="slide"
transition-prev="scale"
transition-next="scale"
swipeable
animated
navigation
padding
height="300px"
control-color="primary"
class="w100"
>
<q-carousel-slide
v-for="(item, idx) in problems"
:key="idx"
:name="item.title"
class="flex justify-center q-pa-none q-ma-none"
>
<problem-section-item
:icon="item.icon"
:title="item.title"
:description="item.description"
style="overflow: hidden; min-width: 100px; max-width: 200px;"
/>
</q-carousel-slide>
</q-carousel>
</div>
</slide-template>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { ref } from 'vue'
import ProblemSectionItem from 'components/ProblemSectionItem.vue'
import SlideTemplate from 'components/SlideTemplate.vue'
const problems = [
{ id: 1, icon: 'mdi-account-group-outline', title: 'problem__address_book', description: 'problem__address_book_description' },
{ id: 2, icon: 'mdi-clipboard-outline', title: 'problem__task_manager', description: 'problem__task_manager_description' },
{ id: 2, icon: 'mdi-clipboard-outline', title: 'problem__tasks', description: 'problem__tasks_description' },
{ id: 3, icon: 'mdi-calendar-month', title: 'problem__meeting', description: 'problem__meeting_description' },
{ id: 4, icon: 'mdi-folder-open-outline', title: 'problem__files', description: 'problem__files_description' },
{ id: 5, icon: 'mdi-lock-outline', title: 'problem__privacy', description: 'problem__privacy_description' }
]
const baseWidth = 250
const containerWidth = ref(0)
const cardWidth = ref(175)
const updateWidth = ({ width }) => {
containerWidth.value = width
cardWidth.value = width < 1200 ? 250 : 175
}
const maxPerRow = computed(() => {
return Math.max(1, Math.floor(containerWidth.value / baseWidth))
})
const rows = computed(() => {
const total = problems.length
const maxRow = maxPerRow.value
if (maxRow >= total) return [problems]
const rowCount = Math.ceil(total / maxRow)
const baseItems = Math.floor(total / rowCount)
const extra = total % rowCount
const result = []
let start = 0
for (let i = 0; i < rowCount; i++) {
const take = baseItems + (i < extra ? 1 : 0)
result.push(problems.slice(start, start + take))
start += take
}
return result
})
const rowClass = (count) => {
return count === 1 ? 'justify-center' : 'justify-between'
}
const itemStyle = (count) => {
return {
flex: `0 0 ${100 / count}%`,
maxWidth: `${100 / count}%`
}
}
const slide = ref(problems[0].title)
</script>

View File

@@ -1,19 +1,19 @@
<template>
<div class="flex column items-center q-pa-md q-ma-md">
<div class="flex column items-center">
<div>
<q-avatar
color="brand"
text-color="white"
:icon
font-size="65px"
size="100px"
font-size="45px"
size="75px"
class="q-my-md"
/>
</div>
<div class="text-bold text-h4">
<div class="text-bold text-h5" align="center">
{{ $t(title) }}
</div>
<div class="text-h6 text-grey-8" style="max-width: 250px; text-align: center;">
<div class="text-grey-8 q-pt-sm" style="text-align: center;">
{{ $t(description) }}
</div>
</div>

View File

@@ -1,6 +1,10 @@
<template>
<div class="flex column no-wrap">
<div class="flex w100 justify-center text-h4 q-mt-md text-bold q-pa-md text-grey">
<div class="flex column no-wrap q-mt-lg">
<div
v-if="title"
class="flex w100 justify-center text-h4 q-mt-md text-bold q-pa-md text-grey"
align="center"
>
{{ $t(title) }}
</div>
<div class="flex w100 justify-center q-pb-md column items-center">

View File

@@ -1,145 +0,0 @@
<template>
<div
id="background-canvas-wrapper"
class="flex fit column bg-brand"
style="opacity:0.65"
>
<canvas id="canvas" class="fit"/>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
onMounted(() => {
const canvasBody = document.getElementById("canvas")
const drawArea = canvasBody.getContext("2d")
const opts = {
particleColor: "rgb(255,255,255)",
lineColor: "rgb(200,200,200)",
particleAmount: 50,
defaultSpeed: 0.1,
variantSpeed: 1,
defaultRadius: 3,
variantRadius: 2,
linkRadius: 200
}
const delay = 200
let tid
const rgb = opts.lineColor.match(/\d+/g)
let w
let h
const particles = []
function resizeReset () {
w = canvasBody.width = window.innerWidth
h = canvasBody.height = window.innerHeight
}
function deBouncer () {
clearTimeout(tid)
tid = setTimeout(function() {
resizeReset()
}, delay)
}
function checkDistance (x1, y1, x2, y2) {
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
}
function setup () {
resizeReset()
for (let i = 0; i < opts.particleAmount; i++){
particles.push(new Particle())
}
window.requestAnimationFrame(loop)
}
function loop() {
window.requestAnimationFrame(loop)
drawArea.clearRect(0, 0, w, h)
for (let i = 0; i < particles.length; i++){
particles[i].update()
particles[i].draw()
}
for (let i = 0; i < particles.length; i++){
linkPoints(particles[i], particles)
}
}
function linkPoints (point1, hubs){
for (let i = 0; i < hubs.length; i++) {
const distance = checkDistance(point1.x, point1.y, hubs[i].x, hubs[i].y)
const opacity = 1 - distance / opts.linkRadius
if (opacity > 0) {
drawArea.lineWidth = 0.5
drawArea.strokeStyle = `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, ${opacity})`
drawArea.beginPath()
drawArea.moveTo(point1.x, point1.y)
drawArea.lineTo(hubs[i].x, hubs[i].y)
drawArea.closePath()
drawArea.stroke()
}
}
}
function Particle () {
this.x = Math.random() * w
this.y = Math.random() * h
this.speed = opts.defaultSpeed + Math.random() * opts.variantSpeed
this.directionAngle = Math.floor(Math.random() * 360)
this.color = opts.particleColor
this.radius = opts.defaultRadius + Math.random() * opts. variantRadius
this.vector = {
x: Math.cos(this.directionAngle) * this.speed,
y: Math.sin(this.directionAngle) * this.speed
};
this.update = function(){
this.border();
this.x += this.vector.x
this.y += this.vector.y
};
this.border = function(){
if (this.x >= w || this.x <= 0) {
this.vector.x *= -1;
}
if (this.y >= h || this.y <= 0) {
this.vector.y *= -1;
}
if (this.x > w) this.x = w
if (this.y > h) this.y = h
if (this.x < 0) this.x = 0
if (this.y < 0) this.y = 0
}
this.draw = function(){
drawArea.beginPath()
drawArea.arc(this.x, this.y, this.radius, 0, Math.PI*2)
drawArea.closePath()
drawArea.fillStyle = this.color
drawArea.fill()
}
}
window.addEventListener("resize", function(){ deBouncer() })
resizeReset()
setup()
})
</script>
<style>
#background-canvas-wrapper {
position: absolute !important;
display: block;
top: 0;
left: 0;
z-index: -1;
margin: 0;
min-height: 100%;
}
</style>

View File

@@ -1 +1 @@
export default { EN: 'EN', RU: 'RU', '': '', main__how_it_works: 'How it works?', main__price: 'Price', main__faq: 'FAQ', main__contacts: 'Contacts', banner__slogan_prepend: 'banner__slogan_prepend', banner__slogan_body: 'banner__slogan_body', banner__main_btn: 'Join!', problem__title: 'problem__title', problem__address_book: 'problem__address_book', problem__address_book_description: 'problem__address_book_description', problem__task_manager: 'problem__task_manager', problem__task_manager_description: 'problem__task_manager_description', problem__meeting: 'problem__meeting', problem__meeting_description: 'problem__meeting_description', problem__files: 'problem__files', problem__files_description: 'problem__files_description', problem__privacy: 'problem__privacy', problem__privacy_description: 'problem__privacy_description', how_it_works__title: 'how_it_works__title', how_works__step1: 'Step 1', how_works__step1_description: 'how_works__step1_description', how_works__step2: 'Step 2', how_works__step2_description: 'how_works__step2_description', how_works__step3: 'Step 3 (optional)', how_works__step3_description: 'how_works__step3_description', how_works__step4: 'Done!', how_works__step4_description: 'how_works__step3_description', how_works__step_user: 'User', how_works__step_admin: 'Administrator', price__title: 'Price', price__chat_per_day: 'price__chat_per_day', price__sale_date: 'price__sale_date', price__stars_pay: 'price__stars_pay', price__stars_description: 'price__stars_description', price_unlimited_users: 'Unlimited users', price_unlimited_projects: 'Unlimited projects', price_free_chats: 'price_free_chats', price_support: 'Support', FAQ__title: 'FAQ', faq__question_1: 'faq__question_1', faq__answer_1: 'faq__answer_1', faq__question_2: 'faq__question_2', faq__answer_2: 'faq__answer_2', faq__question_3: 'faq__question_3', faq__answer_3: 'faq__answer_3', faq__question_4: 'faq__question_4', faq__answer_4: 'faq__answer_4', faq__question_5: 'faq__question_5', faq__answer_5: 'faq__answer_5', footer__docs: 'App documents', footer__doc_terms_of_use: 'Term of use', footer__doc_privacy_policy: 'Privacy Policy', footer__contacts_location: 'Russia, Moscow/Voronezh', footer__description_user_data: 'The site does not collect user data, use cookies, or track user activity.' }
export default { EN: 'EN', RU: 'RU', '': '', main__how_it_works: 'How it works?', main__price: 'Tariff', main__faq: 'FAQ', main__contacts: 'Contacts', banner__slogan_prepend: 'More than just chats', banner__slogan_body: 'Your project\'s workspace in', banner__main_btn: 'Fly', problem__address_book: 'Address Book', problem__address_book_description: 'No more guessing who\'s who.', problem__tasks: 'Tasks', problem__tasks_description: 'Did you agree on something? Lock it in!', problem__meeting: 'Meeting', problem__meeting_description: 'A meeting or a conference call — schedule it right in the chat.', problem__files: 'Files', problem__files_description: 'No need to remember which chat had that file — everything is in one place now.', problem__privacy: 'Access Rights', problem__privacy_description: 'Users can only see information from the chats they are in.', how_it_works__title: 'How it works?', how_works__step1: 'Step 1', how_works__step1_description: 'Create a new project or select an existing one', how_works__step2: 'Step 2', how_works__step2_description: 'Attach a chat to the app', how_works__step3: 'Step 3 (Optional)', how_works__step3_description: 'Set up the address book', how_works__step4: 'Done!', how_works__step4_description: 'Access via the button in the pinned message', how_works__step_user: 'User', how_works__step_admin: 'Administrator', price__title: 'Tariff', price__per_month: 'per month', price__free_tax: 'FREE', price__chats: 'chats', price__stars_pay: 'Payment via', price__stars_description: 'Telegram\'s internal currency', price__tariff_description: 'All plans include full functionality: an unlimited number of users, projects, tasks, and meetings.', FAQ__title: 'Frequently Asked Questions (FAQ)', faq__question_1: 'Who is this app for?', faq__answer_1: 'If you actively communicate on projects in Telegram chats, this app will create a unified information space for you, where you can also connect contractors.', faq__question_2: 'Can I buy a subscription directly, without using Telegram Stars?', faq__answer_2: 'Unfortunately, that\'s not possible. We use Telegram Stars as the only payment system for mini-apps—this is a rule of the platform itself.', faq__question_3: 'Why does the bot need chat admin rights?', faq__answer_3: 'To help you! For the core functions to work—collecting files, creating meeting and task notifications right in the chat—the bot needs rights to read messages and manage messages. This is standard practice for functional bots. We guarantee that your data is confidential and is not shared with third parties (learn more in our Privacy Policy).', faq__question_4: 'Where are my files and data stored?', faq__answer_4: 'Your files and messages remain in your Telegram chats on Telegram\'s servers. We do not store them ourselves. The app merely organizes them, providing convenient search and display.', faq__question_5: 'Why are some contacts in the address book not fully displayed?', faq__answer_5: 'The contact information (name, position, phone, email) is entered into the system by your project\'s administrator. However, for this full data to be displayed to other participants, the user themselves must give their consent upon first launching the app. This is a requirement of personal data protection laws. Thus, you will only see the information that the administrator has added to your book and that the user has permitted to be shown.', faq__question_6: 'What happens if I remove the bot from a chat or stop tracking?', faq__answer_6: 'The app will stop receiving new messages and files from that chat. All previously collected information will remain in your history and will be available for search, but it will no longer update. This is convenient when a project is completed but its archive needs to be preserved.', faq__question_7: 'Can one chat be linked to several projects at once?', faq__answer_7: 'No, one chat can only be linked to one project. This helps maintain order and avoids confusing participants. But you can easily switch between all projects you have access to—even from different administrators.', faq__question_8: 'Can participants of one project see data from another?', faq__answer_8: 'No, all projects are completely independent. This is done for your confidentiality. Information from one project (chats, files, tasks, contacts) never leaks into another. Moreover, the same user can appear in different projects in different roles and from different companies. When switching between projects, you only see the information relevant to the selected project.', faq__description: 'Still have questions? We\'re here to help:', footer__docs: 'App documents', footer__doc_terms_of_use: 'Term of use', footer__doc_privacy_policy: 'Privacy Policy', footer__contacts_location: 'Russia, Moscow/Voronezh', footer__description_user_data: 'The site does not collect user data, use cookies, or track user activity.' }

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,14 @@
<template>
<q-layout view="lHr lpr lFr" class="bg-transparent">
<q-header class="main-content text-grey glass">
<div ref="headerContainer" class="flex q-ma-md justify-between no-wrap items-center">
<q-layout view="lHr lpr lFr" class="bg-transparent relative-position">
<q-header
class="main-content q-py-sm"
:class="isHeroScroll ? 'text-white bg-transparent' : 'text-grey glass'"
reveal
>
<div
ref="headerContainer"
class="flex q-mx-md justify-between no-wrap items-center"
>
<base-logo ref="logo" class="text-h6"/>
<div
ref="menuContainer"
@@ -12,7 +19,7 @@
ref="buttonsContainer"
:class="{ 'invisible absolute': !showFullMenu }"
class="flex row no-wrap"
>
>
<q-btn
v-for="item in menuItems"
:key="item.id"
@@ -20,7 +27,7 @@
no-caps
@click="scrollToElement(item.ref)"
ref="menuButtons"
>
>
<span class="text-no-wrap">{{ $t(item.title) }}</span>
</q-btn>
</div>
@@ -31,7 +38,11 @@
icon="menu"
@click="showDrawer = !showDrawer"
/>
<q-btn outline color="primary" class="q-ml-sm">
<q-btn
outline
:color="isHeroScroll ? 'white' : 'primary'"
class="q-ml-sm"
>
<div class="flex items-center no-wrap">
<span class="text-bold">{{ locale.split('-')[0] }}</span>
</div>
@@ -80,8 +91,9 @@
<q-page-container
class="main-content q-pa-none q-ma-none bg-transparent"
>
<q-scroll-observer axis="vertical" @scroll="updateHeaderStyle"/>
<q-page class="column">
<hero-banner/>
<hero-banner class="q-pa-none" style="margin-top: -58px;" id='hero_banner'/>
<problem-section/>
<how-works-section id='how_works'/>
<price-section id='price'/>
@@ -103,6 +115,12 @@
import FaqSection from 'components/FAQSection.vue'
import FooterSection from 'components/FooterSection.vue'
const isHeroScroll = ref(true)
const updateHeaderStyle = (e) => {
isHeroScroll.value = e.position.top <= 5
}
const showDrawer = ref(false)
const menuItems = [