migrate on nuxt3

This commit is contained in:
2025-06-17 17:46:03 +04:00
parent 7634a3d616
commit 727fa976bd
123 changed files with 20963 additions and 1815 deletions

281
pages/books/[slug].vue Normal file
View File

@ -0,0 +1,281 @@
<template>
<template v-if="book">
<div class="relative z-50 min-h-screen text-white mb-[208px]">
<template v-if="!route.params.titlesSlug">
<!--верхний блок-->
<section
class="flex flex-row relative z-40 before:content-[''] before:absolute before:top-[-140px] before:bg-top before:left-0 before:w-[1280px] before:h-[1000px] before:bg-[url(/assets/img/webp/vino-galante.webp)] before:bg-no-repeat before:bg-contain mt-40"
>
<!--левый блок контента-->
<section class="relative top-[-20px] min-w-[570px]">
<div class="flex flex-col items-center">
<img
:src="book.img"
:alt="book.buttonText"
width="100%"
height="100%"
/>
</div>
</section>
<!--правый блок контента-->
<section>
<div class="w-11/12 h-full flex flex-col justify-start">
<div>
<UiHeading
tag="H1"
class="whitespace-pre-line [&]:font-bold"
size="300"
>
{{ book.title }}
</UiHeading>
<UiParagraph class="mb-10" size="250">
{{ book.subtitle }}
</UiParagraph>
<UiParagraph size="250" class="mb-20">
{{ book.subdesc }}
</UiParagraph>
<UiParagraph size="250" class="whitespace-pre-line min-h-62">
{{ book.description }}
</UiParagraph>
</div>
</div>
</section>
</section>
<!--средний блок-->
<section class="flex flex-row items-center ml-20 justify-between">
<!--левый-->
<div class="flex flex-col items-center min-h-[310px]">
<div class="flex flex-row">
<UiParagraph class="[&]:text-6xl"
>{{ book.price }}&nbsp;</UiParagraph
>
<img src="/img/svg/books/ruble.svg" alt="ruble" />
</div>
<div class="mr-10 flex items-center flex-col gap-3">
<UiButton class="max-w-[380px] !font-normal !px-2 !py-4 mt-24">
{{ book.buttonText }}
</UiButton>
<UiParagraph size="200">
{{ book.buttonFormat }}
</UiParagraph>
</div>
</div>
<!--правый-->
<div class="min-h-[310px]">
<!--о книге-->
<div>
<ul
class="flex flex-row mr-14 items-center justify-between lg:whitespace-nowrap"
>
<li class="flex flex-row mr-14 gap-3 items-center">
<img
src="/img/svg/books/book-pages.svg"
alt="страниц"
width="100%"
height="100%"
/>
<UiParagraph size="250" as="span">
{{ book.pages }}
</UiParagraph>
</li>
<li class="flex flex-row mr-14 gap-3 items-center">
<img
src="/img/svg/books/book-illustrations.svg"
alt="иллюстраций"
width="100%"
height="100%"
/>
<UiParagraph size="250" as="span">
{{ book.illust }}
</UiParagraph>
</li>
<li class="flex flex-row mr-14 gap-3 items-center">
<img
src="/img/svg/books/book-formats.svg"
alt="формат"
width="100%"
height="100%"
/>
<UiParagraph size="250" as="span">
{{ book.format }}
</UiParagraph>
</li>
</ul>
</div>
<!--навигация по книге-->
<div class="mt-24">
<ul
class="flex flex-row mr-32 items-end justify-between lg:whitespace-nowrap"
>
<li class="flex flex-row items-center">
<NuxtLink
to="#"
class="flex flex-col items-center cursor-pointer"
>
<div class="w-[62px] h-[58px]">
<img
src="/img/svg/books/read.svg"
alt="Читай отрывок"
width="62"
height="53"
/>
</div>
<UiParagraph size="250" as="span">
Читай отрывок
</UiParagraph>
</NuxtLink>
</li>
<li class="flex flex-row gap-3 items-center">
<NuxtLink
to="#"
class="flex flex-col items-center gap-4 cursor-pointer"
>
<div class="w-[62px] h-[53px]">
<img
src="/img/svg/books/download.svg"
alt="Скачай отрывок"
width="62"
height="53"
/>
</div>
<UiParagraph size="250" as="span">
Скачай отрывок
</UiParagraph>
</NuxtLink>
</li>
<li class="flex flex-row gap-3 items-center">
<NuxtLink
:to="`/books/${route.params.slug}/${book.hrefTitles}`"
class="flex flex-col items-center gap-3 cursor-pointer"
>
<div class="w-[62px] h-[53px]">
<img
src="/img/svg/books/down2.svg"
alt="Содержание"
width="62"
height="53"
/>
</div>
<UiParagraph size="250" as="span"> Содержание </UiParagraph>
</NuxtLink>
</li>
</ul>
</div>
</div>
</section>
<!--нижний блок-->
<section class="ml-20 mt-32">
<div>
<UiHeading tag="H2" size="300" class="text-three">
Что ты узнаешь
</UiHeading>
<ul class="flex mt-20 flex-row items-center justify-between">
<li
class="flex flex-col-reverse justify-end w-32 gap-4 h-64 items-center transition-transform transform hover:scale-110"
v-for="({ svg, text }, index) in book.whoUKnows"
:key="index"
>
<UiParagraph class="text-center" size="250">
{{ text }}
</UiParagraph>
<img :src="`${svg}`" alt="Вопрос" width="45" height="45" />
</li>
</ul>
</div>
<div class="flex justify-center text-center mt-36">
<UiParagraph>
Или купи на ЛитРес - <br /><a
class="text-three"
:href="book.href"
target="_blank"
>Реферальная ссылка для поддержки автора</a
>
</UiParagraph>
</div>
</section>
</template>
<NuxtPage />
</div>
</template>
<div v-else class="text-white text-center py-20">Книга не найдена.</div>
</template>
<script setup lang="ts">
import { ref, computed, watch } from "vue";
import { useRoute } from "#app";
import UiHeading from "@/components/Typography/UiHeading.vue";
import UiParagraph from "@/components/Typography/UiParagraph.vue";
import UiButton from "@/components/UiButton/UiButton.vue";
interface BookDetail {
id: number;
title: string;
metaTitle: string;
subtitle: string;
subdesc: string;
description: string;
img: string;
price: string;
buttonText: string;
buttonFormat: string;
pages: string;
illust: string;
format: string;
whoUKnows: Array<{
text: string;
svg: string;
}>;
href: string;
hrefTitles: string;
}
const route = useRoute();
const currentBookData = ref<BookDetail | null>(null);
const book = computed(() => currentBookData.value);
const loadBookData = async (slug: string) => {
try {
const module = await import(`./_data/${slug}.json`);
currentBookData.value = module.default as BookDetail;
} catch (error) {
console.error(`Ошибка при загрузке книги с slug '${slug}':`, error);
currentBookData.value = null;
}
};
watch(
() => route.params.slug,
async (newSlug) => {
if (newSlug) {
await loadBookData(newSlug as string);
}
},
{ immediate: true }
);
watch(book, (newBook) => {
if (newBook) {
useHead({
title: `${newBook.metaTitle} | Vino Galante`,
meta: [
{
name: "description",
content: "Онлайн магазин книг автора Vino Galante",
},
],
link: [
{
rel: "canonical",
href: `https://ebook.miduway.space/books/${route.params.slug}`,
},
],
});
}
});
</script>

View File

@ -0,0 +1,172 @@
<template>
<div v-if="titles" class="relative z-50 min-h-screen text-white mb-[208px]">
<section class="flex flex-col relative z-40 mt-40 ml-18">
<UiHeading
tag="H1"
class="whitespace-pre-line [&]:font-normal mb-10 -ml-5"
size="500"
>
{{ titles.title }}
</UiHeading>
<div class="flex flex-col gap-6">
<div
v-for="(section, index) in titles.sections"
:key="index"
class="flex flex-col gap-4"
>
<!-- Main section title -->
<UiHeading tag="H2" size="300" class="text-three [&]:font-normal">
{{ section.title }}
</UiHeading>
<!-- Subsections -->
<div v-if="section.subsections" class="ml-6 flex flex-col gap-4">
<div
v-for="(subsection, subIndex) in section.subsections"
:key="subIndex"
class="flex flex-col gap-2"
>
<!-- Subsection with image -->
<div
v-if="typeof subsection.title === 'object'"
class="flex items-center gap-3 -ml-10"
>
<img
v-if="subsection.title.img"
:src="subsection.title.img"
:alt="subsection.title.text"
class="w-6 h-6"
/>
<UiHeading tag="H3" size="300" class="[&]:font-normal">
{{ subsection.title.text }}
</UiHeading>
</div>
<!-- Regular subsection -->
<UiHeading
v-else
tag="H3"
size="300"
class="[&]:text-gray-200 [&]:font-normal"
>
{{ subsection.title }}
</UiHeading>
<!-- Items list -->
<ul
v-if="subsection.items"
class="ml-6 flex flex-col gap-2 list-decimal"
>
<li
v-for="(item, itemIndex) in subsection.items"
:key="itemIndex"
>
<UiParagraph
size="300"
class="[&]:text-gray-200 [&]:font-normal"
>&nbsp;{{ item }}</UiParagraph
>
</li>
</ul>
<!-- Nested subsections -->
<div v-if="subsection.subsections" class="flex flex-col gap-2">
<div
v-for="(nestedSub, nestedIndex) in subsection.subsections"
:key="nestedIndex"
>
<UiHeading
tag="H4"
size="300"
class="[&]:text-gray-200 [&]:font-normal"
>
{{ nestedSub.title }}
</UiHeading>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
<div v-else class="text-white text-center py-20">Содержание не найдено.</div>
</template>
<script setup lang="ts">
import { ref, computed, watch } from "vue";
import { useRoute } from "vue-router";
import UiHeading from "@/components/Typography/UiHeading.vue";
import UiParagraph from "@/components/Typography/UiParagraph.vue";
// import { useHead } from '@vueuse/head'
interface SubsectionTitle {
text: string;
img?: string;
}
interface Subsection {
title: string | SubsectionTitle;
items?: string[];
subsections?: Array<{
title: string;
}>;
}
interface Section {
title: string;
subsections?: Subsection[];
}
interface TitlesData {
title: string;
titleMeta: string;
sections: Section[];
}
const route = useRoute();
const currentTitlesData = ref<TitlesData | null>(null);
const titles = computed(() => currentTitlesData.value);
const loadTitlesData = async (slug: string) => {
try {
const module = await import(`./_data/${slug}.json`);
currentTitlesData.value = module.default as TitlesData;
} catch (error) {
console.error(`Ошибка при загрузке содержания с slug '${slug}':`, error);
currentTitlesData.value = null;
}
};
watch(
() => route.params.titlesSlug,
async (newSlug) => {
if (newSlug) {
await loadTitlesData(newSlug as string);
}
},
{ immediate: true }
);
watch(titles, (newTitles) => {
if (newTitles) {
useHead({
title: `${newTitles.titleMeta} | Vino Galante`,
meta: [
{
name: "description",
content: "Содержание книги Vino Galante",
},
],
link: [
{
rel: "canonical",
href: `https://ebook.miduway.space/books/${route.params.slug}/${route.params.titlesSlug}`,
},
],
});
}
});
</script>

View File

@ -0,0 +1,187 @@
{
"id": "title-1",
"title": "Оглавление",
"titleMeta": "Оглавление - Книга I",
"sections": [
{
"title": "Благодарности"
},
{
"title": "Введение",
"subsections": [
{
"title": "Работа с любым печатным материалом"
}
]
},
{
"title": "Глава 1. Перезагрузка",
"subsections": [
{
"title": "Введение"
},
{
"title": {
"text": "Убеждения соблазнительницы",
"img": "/img/svg/books/1/titles-1/flowbite_wine-glass-solid.svg"
},
"items": [
"Всё всегда хорошо",
"Другие девушки не помеха для меня",
"Парней много, я одна",
"Использовать мужчин это естественно и приятно",
"Отшивать мужчин это естественно",
"Ты имеешь ровно то, что заслужила",
"Ты достойна гораздо больше того, что имеешь на данный момент",
"Все, о чем ты способна мечтать, ты способна иметь",
"Проявлять активность успешной девушке естественно",
"Все мужчины, с которыми ты общаешься до замужества всего лишь твои тренажеры",
"Мужчина должен относиться к тебе уважительно",
"Среди мужчин встречается идиоты",
"Тебе выгодно, если мужчина хочет тебя",
"Мужчина общается с тобой только тогда, когда ему от тебя что-то нужно",
"Пока мужчина тебя не трахнул, ты не проиграла",
"Если ты получаешь удовольствие от общения с мужчиной все идет по плану",
"Ты ничего не должна мужчине, даже если он подарил тебе дворец и яхту",
"Соблазнение всего лишь очень интересная игра, в которой нет проигравших",
"У мужчин две ахиллесовых пяты это и секс. Это в сто раз важнее секса",
"Мужчины очень хорошие создания",
"Мужчины не примитивные",
"Мужчинам нужен далеко не только секс (Мужчине нужен от тебя только секс, если ты больше ничего ему дать не можешь)",
"Смысл жизни развитие",
"Иметь запасной аэродром правильно и естественно для женщины",
"Сексом мужчину не удержать",
"Общение с мужчиной должно приносить радость",
"Мужчины стремятся не к хорошим, а к высокоранговым женщинам",
"Мир вокруг тебя отражение тебя самой"
]
},
{
"title": {
"text": "Секс на первом свидании",
"img": "/img/svg/books/1/titles-1/healthicons_sexual-reproductive-health.svg"
}
}
]
},
{
"title": "Глава 2. Свобода",
"subsections": [
{
"title": "Введение"
},
{
"title": {
"text": "Поля-тараканы",
"img": "/img/svg/books/1/titles-1/simple-icons_cockroachlabs.svg"
}
},
{
"title": "Техника безопасности при работе в полях"
},
{
"title": "Восстановление сил"
},
{
"title": "Главный принцип развития"
},
{
"title": "Техники выхода в аптайм"
},
{
"title": "Действия"
},
{
"title": "Результат"
},
{
"title": {
"text": "Калибровка",
"img": "/img/svg/books/1/titles-1/material-symbols_editor-choice-rounded.svg"
},
"subsections": [
{
"title": "Азбука калибровки"
},
{
"title": "Как наблюдать, не вызывая подозрений"
}
]
},
{
"title": {
"text": "Стратегия сближений",
"img": "/img/svg/books/1/titles-1/ph_strategy-fill.svg"
},
"subsections": [
{
"title": "Определение и классификация"
},
{
"title": "Псевдопассивная. Этап первый"
},
{
"title": "Псевдопассивная. Этап второй"
},
{
"title": "Активный тип стратегии"
},
{
"title": "Третий этап. Степени кокетства"
}
]
}
]
},
{
"title": "Глава 3. Затравка",
"subsections": [
{
"title": "Введение"
},
{
"title": {
"text": "Теория женской привлекательности",
"img": "/img/svg/books/1/titles-1/icon-park-outline_women.svg"
},
"subsections": [
{
"title": "Введение"
}
]
},
{
"title": "Физическое здоровье"
},
{
"title": "Ментальный посыл. Стильность"
},
{
"title": "Ментальный посыл. Внутреннее ощущение мира"
},
{
"title": {
"text": "Ошибки резидента",
"img": "/img/svg/books/1/titles-1/si_error-line.svg"
},
"items": [
"Косак 1",
"Косак 2",
"Полукосак 3",
"Косак 4",
"МетаКосак 5 опасный",
"МетаКосак 6 опасный",
"Косак 7",
"МетаКосак 8 крайне опасно",
"МетаКосак 9 опасно",
"Косак 10",
"Косак 11"
]
},
{
"title": "В следующей книге"
}
]
}
]
}

View File

@ -0,0 +1,170 @@
{
"id": "title-1",
"title": "Оглавление",
"titleMeta": "Оглавление - Книга II",
"sections": [
{
"title": "Введение"
},
{
"title": "Глава 1. Перед боем",
"subsections": [
{
"title": {
"text": "Закон Вино Галанте или закон неотвратимости успеха",
"img": "/img/svg/books/2/titles-2/octicon_law-24.svg"
}
},
{
"title": {
"text": "Запасной аэродром",
"img": "/img/svg/books/2/titles-2/mingcute_airplane-line.svg"
},
"subsections": [
{
"title": "Экскурс в историю"
},
{
"title": "Правила формирования запасного аэродрома"
},
{
"title": "Подробнее о пятом пункте или как не врать"
},
{
"title": "Следствия наличия запасного аэродрома"
}
]
},
{
"title": {
"text": "Свидания",
"img": "/img/svg/books/2/titles-2/mdi_heart-outline (1).svg"
},
"subsections": [
{
"title": "Одежда"
},
{
"title": "Правильные места для свиданий"
},
{
"title": "Самое важное в свиданиях"
}
]
}
]
},
{
"title": "Глава 2. Ближний бой",
"subsections": [
{
"title": "Введение"
},
{
"title": {
"text": "Техника влюбления",
"img": "/img/svg/books/2/titles-2/Vector (4).svg"
},
"items": [
"Механизм мужской и женской влюбленностей",
"Главный секрет влюбления",
"Ментальная подстройка",
"Подстройка по ценностям",
"Качество девушки",
"Поведение",
"Как правильно хвалить мужчину",
"Игра “Ближе-дальше”",
"Дикий крышечок “Полярный разрыв”",
"Полярный разрыв в действии или крышечок на грани фола",
"Фишка “Рассмеяться как зло”",
"Фишка “АХ”",
"Техника влюбления “Отмененная помощь”",
"Техника влюбления “Не тот поворот”",
"Техника влюбления “Неожиданный разрыв”",
"Техника влюбления “Обещанный звонок”",
"Техника влюбления “Парень подружка”",
"Фишка “Бросок кобры”",
"Фишка “Мягкий язык”",
"Вызов ревности"
]
},
{
"title": {
"text": "Типичные неэффективные фишки девушек",
"img": "/img/svg/books/2/titles-2/Group.svg"
},
"items": ["Я выхожу замуж", "Я скучаю по парню", "Желание казаться круче, чем ты есть"]
},
{
"title": {
"text": "Чего никогда нельзя делать",
"img": "/img/svg/books/2/titles-2/Group (1).svg"
},
"subsections": [
{
"title": "Введение"
},
{
"title": "Оральные ласки"
},
{
"title": "Минет"
}
]
},
{
"title": {
"text": "СМС-переписка",
"img": "/img/svg/books/2/titles-2/Vector (6).svg"
},
"subsections": [
{
"title": "Российские школы соблазнения"
},
{
"title": "Как найти соблазнителя"
},
{
"title": "История рождения одного термина"
}
]
},
{
"title": {
"text": "Секс и девичья невинность",
"img": "/img/svg/books/2/titles-2/Vector (7).svg"
},
"subsections": [
{
"title": "Как парни воспринимают секс"
},
{
"title": "Девичья невинность"
},
{
"title": "Прожим девственницы. Метод Галанте."
},
{
"title": "Прожим девственницы. Классический метод."
},
{
"title": "Прожим девственницы. Метод пикапера."
},
{
"title": "Вместо эпилога"
}
]
},
{
"title": "Что делать, если попался «сложный красавчик»"
},
{
"title": {
"text": "Словарь",
"img": "/img/svg/books/2/titles-2/Vector (8).svg"
}
}
]
}
]
}

39
pages/books/_data/1.json Normal file
View File

@ -0,0 +1,39 @@
{
"id": 1,
"title": "Как влюбить в себя любого\nКнига I",
"metaTitle": "Как влюбить в себя любого - Книга I",
"subtitle": "ОТКРОВЕНИЯ БЫВШЕГО КАЗАНОВЫ",
"subdesc": "💡 Ты красивая, умная, но он не пишет? Эта книга покажет, как влюбить в себя любого — без игр и унижений",
"description": "Думаешь Vino Galante - правнук легендарного Джакомо Казановы? Да, такие слухи ходят. Но здесь дело не в итальянской крови. Просто Galante - очень «тонкий» соблазнитель. Зная все тонкости этого искусства, он филигранно работает «кончиками пальцев».\n\nА эту книгу (ты не поверишь!!) он написал специально для девушек. Однажды влюбившись, Vino перестал соблазнять. Так у тебя появилась возможность узнать основы тонкого искусства соблазнения из легендарного первоисточника.",
"img": "/img/webp/books/1.webp",
"price": "520 ",
"buttonText": "Хочу знать, как работает мужская психология",
"buttonFormat": "PDF + EPUB сразу после оплаты",
"pages": "210 страниц",
"illust": "11 иллюстраций",
"format": "PDF + EPUB",
"whoUKnows": [
{
"text": "Как устроено мужское влечение на самом деле",
"svg": "/img/svg/books/1/mdi_heart-outline.svg"
},
{
"text": "Почему красивые девушки часто одиноки — и что с этим делать",
"svg": "/img/svg/books/1/f7_exclamationmark.svg"
},
{
"text": "Как флиртовать тонко, не теряя себя",
"svg": "/img/svg/books/1/meteor-icons_message.svg"
},
{
"text": "Что делает девушку запоминающейся",
"svg": "/img/svg/books/1/lucide_star.svg"
},
{
"text": "Как не попадать в «запас» и быть единственной",
"svg": "/img/svg/books/1/stash_target.svg"
}
],
"href": "https://www.litres.ru/58125553/",
"hrefTitles": "title-1"
}

39
pages/books/_data/2.json Normal file
View File

@ -0,0 +1,39 @@
{
"id": 2,
"title": "Как влюбить в себя любого\nКнига II",
"metaTitle": "Как влюбить в себя любого - Книга II",
"subtitle": "ТОНКАЯ ИГРА",
"subdesc": "💡 Если ты устала от “не готов к отношениям” — начни играть по своим правилам",
"description": "Ты бывала свидетелем такого, что у красивой девушки личная жизнь не складывается, а у, казалось бы, дурнушки и семья хорошая, и муж и любит, и обеспечивает? Да такое сплошь и рядом!\n\nХочешь узнать, как построить отношения с любым парнем в наш век, когда вокруг полно красавиц, а все мужчины/парни избалованы?\nОтветы ты найдешь в этой книге.",
"img": "/img/webp/books/2.webp",
"price": "520 ",
"buttonText": "Скачать сейчас — и начать менять игру",
"buttonFormat": "PDF + EPUB сразу после оплаты",
"pages": "210 страниц",
"illust": "11 иллюстраций",
"format": "PDF + EPUB",
"whoUKnows": [
{
"text": "Как выстроить притяжение с любым мужчиной",
"svg": "/img/svg/books/1/mdi_heart-outline.svg"
},
{
"text": "Как включить его чувства, а не просто понравиться",
"svg": "/img/svg/books/1/f7_exclamationmark.svg"
},
{
"text": "Какие фишки работают — и почему",
"svg": "/img/svg/books/1/meteor-icons_message.svg"
},
{
"text": "Почему мужчины уходят от «идеальных» и возвращаются к «опасным»",
"svg": "/img/svg/books/1/lucide_star.svg"
},
{
"text": "Как говорить и вести себя, чтобы остаться в его сердце",
"svg": "/img/svg/books/1/stash_target.svg"
}
],
"href": "https://www.litres.ru/vino-galante/kak-vlubit-v-sebya-lubogo-tonkaya-igra/",
"hrefTitles": "title-2"
}