176 lines
4.4 KiB
Vue
176 lines
4.4 KiB
Vue
<template>
|
|
<div v-if="content" class="relative z-50 min-h-screen text-white mb-[208px] ml-4">
|
|
<section class="flex flex-col relative z-40 mt-40 ml-18 mr-18">
|
|
<div v-html="renderedContent" class="prose prose-invert max-w-none"></div>
|
|
</section>
|
|
</div>
|
|
<div v-else class="text-white text-center py-20">Глава не найдена.</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
// Получаем параметры из URL
|
|
const route = useRoute()
|
|
const bookSlug = route.params.slug as string
|
|
const chapterSlug = route.params.chapter as string
|
|
|
|
// Загружаем контент из markdown файла
|
|
const { data: content } = await useAsyncData(`book-${bookSlug}-${chapterSlug}`, () => {
|
|
return $fetch(`/api/content/books/${chapterSlug}`)
|
|
})
|
|
|
|
// Конвертируем markdown в HTML (простая реализация)
|
|
const renderedContent = computed(() => {
|
|
if (!content.value?.content) return ''
|
|
|
|
let html = content.value.content
|
|
|
|
// Заменяем заголовки
|
|
html = html.replace(
|
|
/^### (.*$)/gim,
|
|
'<h3 style="color: #f54b7e; font-weight: bold; margin-top: 1.5rem; margin-bottom: 0.5rem;">$1</h3>',
|
|
)
|
|
html = html.replace(
|
|
/^## (.*$)/gim,
|
|
'<h2 style="color: #f54b7e; font-weight: bold; margin-top: 2rem; margin-bottom: 1rem;">$1</h2>',
|
|
)
|
|
html = html.replace(
|
|
/^# (.*$)/gim,
|
|
'<h1 style="color: #f54b7e; font-weight: bold; font-size: 1.5em; margin-bottom: 1rem;">$1</h1>',
|
|
)
|
|
|
|
// Заменяем параграфы
|
|
html = html.replace(
|
|
/^  (.*$)/gim,
|
|
'<p style="margin-bottom: 1rem; line-height: 1.6;">$1</p>',
|
|
)
|
|
|
|
// Заменяем жирный текст (двойные звездочки)
|
|
html = html.replace(/\*\*(.*?)\*\*/g, '<strong style=" font-weight: bold;">$1</strong>')
|
|
|
|
// Заменяем курсив (звездочки)
|
|
html = html.replace(/\*(.*?)\*/g, '<em style="font-style: italic;">$1</em>')
|
|
|
|
// Заменяем курсив (подчеркивания)
|
|
html = html.replace(/\_(.*?)\_/g, '<em style="font-style: italic;">$1</em>')
|
|
|
|
// Заменяем изображения - исправляем пути
|
|
html = html.replace(
|
|
/!\[([^\]]*)\]\(([^)]+)\)/g,
|
|
'<img src="/img/books/$2" alt="$1" style="max-width: 100%; height: auto; margin: 1rem 0; display: block;" />',
|
|
)
|
|
|
|
// Заменяем списки
|
|
html = html.replace(/^- (.*$)/gim, '<li style="margin-bottom: 0.5rem;">$1</li>')
|
|
html = html.replace(/(<li.*<\/li>)/s, '<ul style="margin-bottom: 1rem;">$1</ul>')
|
|
|
|
// Заменяем <br/> теги на HTML <br>
|
|
html = html.replace(/<br\/>/g, '<br>')
|
|
|
|
// Заменяем переносы строк
|
|
html = html.replace(/\n/g, '<br>')
|
|
|
|
return html
|
|
})
|
|
|
|
// Устанавливаем мета-теги
|
|
useHead({
|
|
title: `Глава ${chapterSlug} | Книга ${bookSlug} | Vino Galante`,
|
|
meta: [
|
|
{
|
|
name: 'description',
|
|
content: `Читайте главу ${chapterSlug} из книги ${bookSlug} автора Vino Galante`,
|
|
},
|
|
],
|
|
link: [
|
|
{
|
|
rel: 'canonical',
|
|
href: `https://ebook.miduway.space/books/${bookSlug}/chapters/${chapterSlug}`,
|
|
},
|
|
],
|
|
})
|
|
|
|
// Обработка ошибок, если файл не найден
|
|
if (!content.value) {
|
|
throw createError({
|
|
statusCode: 404,
|
|
statusMessage: 'Глава не найдена',
|
|
})
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
/* Дополнительные стили для контента */
|
|
.prose {
|
|
color: white;
|
|
max-width: none;
|
|
}
|
|
|
|
.prose h1 {
|
|
color: #f54b7e;
|
|
font-weight: bold;
|
|
font-size: 1.5em;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.prose h2 {
|
|
color: #f54b7e;
|
|
font-weight: bold;
|
|
margin-top: 2rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.prose h3 {
|
|
color: #f54b7e;
|
|
font-weight: bold;
|
|
margin-top: 1.5rem;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.prose p {
|
|
margin-bottom: 1rem;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.prose ul {
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.prose li {
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.prose strong {
|
|
font-weight: bold;
|
|
}
|
|
|
|
.prose em {
|
|
font-style: italic;
|
|
}
|
|
|
|
.prose blockquote {
|
|
border-left: 4px solid #f54b7e;
|
|
padding-left: 1rem;
|
|
margin: 1rem 0;
|
|
font-style: italic;
|
|
}
|
|
|
|
.prose img {
|
|
max-width: 100%;
|
|
height: auto;
|
|
margin: 1rem 0;
|
|
display: block;
|
|
border-radius: 8px;
|
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
/* Стили для подписей к изображениям */
|
|
.prose img + br + em {
|
|
display: block;
|
|
text-align: center;
|
|
font-style: italic;
|
|
color: #f54b7e;
|
|
margin-top: 0.5rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
</style>
|