add. Closes #8
All checks were successful
Deploy Nuxt App / deploy (push) Successful in 3m59s

This commit is contained in:
2025-06-21 10:21:05 +04:00
parent 5c97679188
commit 925b6197f2
16 changed files with 380 additions and 30 deletions

View File

@ -33,7 +33,7 @@
</section>
</section>
<!--средний блок-->
<section class="flex flex-row items-center ml-12 gap-24">
<section class="flex flex-row items-center ml-12 gap-24 relative z-50">
<!--левый-->
<div class="flex flex-col items-center min-h-[310px]">
<div class="flex flex-row">
@ -41,7 +41,12 @@
<img src="/img/svg/books/ruble.svg" alt="ruble" />
</div>
<div class="flex items-center flex-col gap-3">
<UiButton class="max-w-[440px] !font-normal !px-2 !py-4 mt-16">
<UiButton
@click="handleSelect"
:id="book.id"
variants="primary"
class="max-w-[440px] !font-normal !px-2 !py-4 mt-16"
>
{{ book.buttonText }}
</UiButton>
<UiParagraph size="200">
@ -153,10 +158,11 @@
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { useRoute } from '#app'
import { useRoute, useRouter } from '#app'
import UiHeading from '@/components/Typography/UiHeading.vue'
import UiParagraph from '@/components/Typography/UiParagraph.vue'
import UiButton from '@/components/UiButton/UiButton.vue'
import { useSelectedBook } from '@/store/useSelectedBook'
interface BookDetail {
id: number
@ -182,6 +188,8 @@ interface BookDetail {
const route = useRoute()
const router = useRouter()
const currentBookData = ref<BookDetail | null>(null)
const book = computed(() => currentBookData.value)
@ -196,6 +204,10 @@ const loadBookData = async (slug: string) => {
}
}
const handleSelect = () => {
router.push('/cart/')
}
watch(
() => route.params.slug,
async (newSlug) => {

View File

@ -1,17 +1,21 @@
{
"title": "Корзина",
"items": [
{
"id": 1,
"name": "Как влюбить в себя любого \n Книга I. \n Откровения бывшего Казановы",
"src": "/assets/img/png/book1.png",
"buy": "добавить Книгу I"
"src": "/img/books/book1.png",
"buy": "добавить Книгу I",
"price": 520,
"message": "💡 Купи обе книги и получи \n скидку 10% - 936 за комплект"
},
{
"id": 2,
"name": "Как влюбить в себя любого \n Книга II. \n Тонкая игра",
"src": "/assets/img/png/book2.png",
"buy": "добавить Книгу II"
"src": "/img/books/book2.png",
"buy": "добавить Книгу II",
"price": 520,
"message": "💡 Купи обе книги и получи \n скидку 10% - 936 за комплект"
}
],
"message": "💡 Купи обе книги и получи скидку 10% - 936 за комплект",
"price": "520 ₽"
"message": "💡 Купи обе книги и получи скидку 10% - 936 за комплект"
}

View File

@ -1,8 +1,113 @@
<template>
<section class="relative z-50">
<UiHeading tag="h1" size="300"> Корзина </UiHeading>
<section class="relative z-50 ml-4">
<UiHeading tag="h1" size="300" class="font-bold mb-16"> Корзина </UiHeading>
<div class="-ml-6">
<div
v-for="({ name, src, price, message, buy, id }, index) in cartList.items"
:key="index"
class="flex items-center mb-24"
>
<div class="w-40 h-40">
<img :src="`${src}`" alt="book" />
</div>
<UiParagraph size="300" class="whitespace-pre mb-10 mr-12 w-80">{{ name }}</UiParagraph>
<UiParagraph size="300" class="whitespace-pre mb-10 mr-20">{{ message }}</UiParagraph>
<UiButton
:id="id"
class="mb-10"
v-if="store.getQuantity(id) === 0"
@click="handleAddToCart(id)"
>{{ buy }}</UiButton
>
<template v-else>
<div class="flex items-center gap-8 mr-20">
<button
class="w-8 h-8 flex items-center justify-center rounded-full border border-white text-white text-2xl"
@click="handleRemove(id)"
aria-label="Уменьшить количество"
>
</button>
<span class="text-white text-2xl">{{ store.getQuantity(id) }}</span>
<button
class="w-8 h-8 flex items-center justify-center rounded-full border border-white text-white text-2xl"
@click="handleIncrement(id)"
aria-label="Увеличить количество"
>
+
</button>
</div>
<span class="text-white text-2xl font-bold mr-20 whitespace-nowrap">
{{ Number(price) * store.getQuantity(id) }}
</span>
<button
class="w-8 h-8 flex items-center justify-center rounded-full border border-white text-white text-xl"
@click="handleRemove(id)"
aria-label="Удалить товар"
>
×
</button>
</template>
</div>
<div class="flex items-center justify-end mt-8">
<UiParagraph is="span" size="300">Общая стоимость</UiParagraph>
<template v-if="isSpecialPrice">
<span class="text-white text-2xl font-bold ml-4 line-through select-none">
{{ regularTotalPrice }}
</span>
<span class="text-primary text-3xl font-bold ml-4">
{{ store.getTotalPrice(cartList.items) }}
</span>
</template>
<template v-else>
<span class="text-primary text-3xl font-bold ml-4">
{{ store.getTotalPrice(cartList.items) }}
</span>
</template>
</div>
</div>
<div class="mt-10 flex flex-col items-center justify-center">
<UiButton class="w-[660px]"> перейти к оформлению </UiButton>
<UiParagraph is="span" size="300" class="mb-10 mt-5"
>После оплаты книги сразу будут доступны для скачивания</UiParagraph
>
</div>
</section>
</template>
<script setup lang="ts">
import cartList from './_data/cart.json'
import UiHeading from '~/components/Typography/UiHeading.vue'
import UiParagraph from '~/components/Typography/UiParagraph.vue'
import { useSelectedBook } from '@/store/useSelectedBook'
import { computed } from 'vue'
const store = useSelectedBook()
function handleIncrement(id: number) {
store.increment(id)
}
function handleDecrement(id: number) {
store.decrement(id)
}
function handleRemove(id: number) {
store.reset(id)
}
function handleAddToCart(id: number) {
store.addToCart(id)
}
const selectedBooksCount = computed(() => store.cartQuantities.filter((i) => i.quantity > 0).length)
const isSpecialPrice = computed(() => selectedBooksCount.value === 2)
const regularTotalPrice = computed(() => {
// Сумма без скидки
return store.cartQuantities.reduce((sum, item) => {
const book = cartList.items.find((b: any) => b.id === item.id)
return sum + (book ? Number(book.price) * item.quantity : 0)
}, 0)
})
</script>

19
pages/email.vue Normal file
View File

@ -0,0 +1,19 @@
<template>
<div class="relative z-50 text-black min-h-screen py-12">
<div class="container mx-auto px-4">
<div class="text-center mb-8">
<UiHeading tag="h1" size="500" class="font-bold text-primary mb-4"
>Контактные данные</UiHeading
>
</div>
<EmailForm />
</div>
</div>
</template>
<script setup>
import UiHeading from '~/components/Typography/UiHeading.vue'
// Страница использует компонент EmailForm
</script>

View File

@ -1,12 +1,14 @@
import UiParagraph from '@/components/Typography/UiParagraph.vue';
<template>
<div
v-for="({ topContent, button, botContent }, index) in content.data"
v-for="({ topContent, button, botContent, path }, index) in content.data"
:key="index"
class="flex flex-col items-center max-w-96"
>
<UiParagraph size="300" class="mb-12 h-32">{{ topContent }} </UiParagraph>
<UiButton variants="primary" class="mb-3 w-full">{{ button }} </UiButton>
<UiButton tag="RouterLink" :to="path" variants="primary" class="mb-3 w-full"
>{{ button }}
</UiButton>
<UiParagraph as="span" size="200"> {{ botContent }}</UiParagraph>
</div>
</template>
@ -23,12 +25,14 @@ const content = reactive({
'💡 Узнай, как думает мужчина, что его действительно цепляет, и что делает женщину незабываемой.',
button: 'КУПИТЬ КНИГУ I',
botContent: 'PDF + EPUB сразу после оплаты',
path: '/books/1',
},
{
topContent:
'💡 Продолжение для тех, кто готов перейти от флирта к глубокому контакту. Как строить притяжение, не теряя себя.',
button: 'КУПИТЬ КНИГУ II',
botContent: 'PDF + EPUB сразу после оплаты',
path: '/books/2',
},
],
})